fix(ui): improve scan status handling (again) (#4115)

This commit is contained in:
Deluan Quintão
2025-05-24 21:26:05 -04:00
committed by GitHub
parent c98e4d02cb
commit b722f0dcfc
4 changed files with 45 additions and 24 deletions
+4 -16
View File
@@ -1,5 +1,5 @@
import React, { useState, useEffect } from 'react' import React, { useState, useEffect } from 'react'
import { useDispatch, useSelector } from 'react-redux' import { useSelector } from 'react-redux'
import { useNotify, useTranslate } from 'react-admin' import { useNotify, useTranslate } from 'react-admin'
import { import {
Popover, Popover,
@@ -15,11 +15,11 @@ import {
Typography, Typography,
} from '@material-ui/core' } from '@material-ui/core'
import { FiActivity } from 'react-icons/fi' 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 { VscSync } from 'react-icons/vsc'
import { GiMagnifyingGlass } from 'react-icons/gi' import { GiMagnifyingGlass } from 'react-icons/gi'
import subsonic from '../subsonic' import subsonic from '../subsonic'
import { scanStatusUpdate } from '../actions' import { useInitialScanStatus } from './useInitialScanStatus'
import { useInterval } from '../common' import { useInterval } from '../common'
import { useScanElapsedTime } from './useScanElapsedTime' import { useScanElapsedTime } from './useScanElapsedTime'
import { formatDuration, formatShortDuration } from '../utils' import { formatDuration, formatShortDuration } from '../utils'
@@ -80,24 +80,12 @@ const ActivityPanel = () => {
const notify = useNotify() const notify = useNotify()
const [anchorEl, setAnchorEl] = useState(null) const [anchorEl, setAnchorEl] = useState(null)
const open = Boolean(anchorEl) const open = Boolean(anchorEl)
const dispatch = useDispatch() useInitialScanStatus()
const handleMenuOpen = (event) => setAnchorEl(event.currentTarget) const handleMenuOpen = (event) => setAnchorEl(event.currentTarget)
const handleMenuClose = () => setAnchorEl(null) const handleMenuClose = () => setAnchorEl(null)
const triggerScan = (full) => () => subsonic.startScan({ fullScan: full }) 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(() => { useEffect(() => {
if (serverStart.version && serverStart.version !== config.version) { if (serverStart.version && serverStart.version !== config.version) {
notify('ra.notification.new_version', 'info', {}, false, 604800000 * 50) notify('ra.notification.new_version', 'info', {}, false, 604800000 * 50)
+18
View File
@@ -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])
}
+9 -8
View File
@@ -6,16 +6,17 @@ export const useScanElapsedTime = (scanning, elapsedTime) => {
const prevScanningRef = useRef(scanning) const prevScanningRef = useRef(scanning)
useEffect(() => { useEffect(() => {
// Only update from server when scan starts or stops
const prevScanning = prevScanningRef.current const prevScanning = prevScanningRef.current
if (!prevScanning && scanning) { const serverElapsed = Number(elapsedTime) || 0
// Scan just started - initialize with server value
setElapsed(Number(elapsedTime) || 0) if (scanning !== prevScanning) {
} else if (prevScanning && !scanning) { // Scan has just started or stopped - sync with server value
// Scan just finished - use final server value setElapsed(serverElapsed)
setElapsed(Number(elapsedTime) || 0) } else if (!scanning) {
// Not scanning -> always reflect server value (initial load or after finish)
setElapsed(serverElapsed)
} }
// Update ref for next comparison
prevScanningRef.current = scanning prevScanningRef.current = scanning
}, [scanning, elapsedTime]) }, [scanning, elapsedTime])
+14
View File
@@ -70,6 +70,20 @@ describe('useScanElapsedTime', () => {
expect(result.current).toBe(12e9) 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', () => { it('ignores server updates during scanning', () => {
const { result, rerender } = renderHook( const { result, rerender } = renderHook(
({ scanning, elapsed }) => useScanElapsedTime(scanning, elapsed), ({ scanning, elapsed }) => useScanElapsedTime(scanning, elapsed),