fixed timeout issue

This commit is contained in:
2026-06-02 14:26:13 -04:00
parent 50cd3ecc6c
commit 64ed8b81c1
6 changed files with 154 additions and 52 deletions
+1 -2
View File
@@ -2,9 +2,8 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>dashboard</title>
<title>Test House Dashboard</title>
</head>
<body>
<div id="root"></div>
+67 -23
View File
@@ -1,8 +1,41 @@
import { useState, useEffect } from 'react'
import { useState, useEffect, useRef, useCallback } from 'react'
import { useQueryClient } from '@tanstack/react-query'
import { useConfig, useSaveConfig } from '../hooks/useConfig'
import { apiFetch } from '../lib/api'
function useScanPoller(onDone) {
const timerRef = useRef(null)
const onDoneRef = useRef(onDone)
onDoneRef.current = onDone
const stop = useCallback(() => {
if (timerRef.current) {
clearInterval(timerRef.current)
timerRef.current = null
}
}, [])
const start = useCallback(() => {
stop()
timerRef.current = setInterval(async () => {
try {
const data = await apiFetch('/scan-status')
if (!data?.scanning) {
stop()
onDoneRef.current()
}
} catch {
stop()
onDoneRef.current()
}
}, 2000)
}, [stop])
useEffect(() => () => stop(), [stop])
return { start, stop }
}
function fmtSeconds(s) {
if (s == null) return ''
const m = Math.round(parseFloat(s) / 60)
@@ -14,12 +47,20 @@ export default function ConfigModal({ onClose }) {
const { data: config, isLoading } = useConfig()
const { mutate: save, isPending } = useSaveConfig()
const [form, setForm] = useState({})
const [scanResult, setScanResult] = useState(null) // { testCount, completedCount } | null
const [saveError, setSaveError] = useState(null)
const [form, setForm] = useState({})
const [scanResult, setScanResult] = useState(null)
const [saveError, setSaveError] = useState(null)
const [isRescanning, setIsRescanning] = useState(false)
const [isScanning, setIsScanning] = useState(false)
const [isSavingTimes, setIsSavingTimes] = useState(false)
const scanPoller = useScanPoller(() => {
queryClient.invalidateQueries({ queryKey: ['stats'] })
queryClient.invalidateQueries({ queryKey: ['tests'] })
setIsRescanning(false)
setIsScanning(false)
})
useEffect(() => {
if (config) {
setForm({
@@ -55,10 +96,9 @@ export default function ConfigModal({ onClose }) {
}
save(payload, {
onSuccess: (data) => {
if (data?.testCount !== null && data?.testCount !== undefined) {
setScanResult({ testCount: data.testCount, completedCount: data.completedCount })
// Auto-close after showing result only if tests were found
if (data.testCount > 0) setTimeout(onClose, 1500)
if (data?.scanning) {
setIsScanning(true)
scanPoller.start()
} else {
onClose()
}
@@ -98,14 +138,15 @@ export default function ConfigModal({ onClose }) {
setIsRescanning(true)
try {
const data = await apiFetch('/config/rescan-results', { method: 'POST' })
if (data?.testCount !== null && data?.testCount !== undefined) {
setScanResult({ testCount: data.testCount, completedCount: data.completedCount })
if (data?.scanning) {
scanPoller.start()
} else {
setIsRescanning(false)
queryClient.invalidateQueries({ queryKey: ['stats'] })
queryClient.invalidateQueries({ queryKey: ['tests'] })
}
queryClient.invalidateQueries({ queryKey: ['stats'] })
queryClient.invalidateQueries({ queryKey: ['tests'] })
} catch (err) {
setSaveError(err?.message ?? 'Rescan failed')
} finally {
setIsRescanning(false)
}
}
@@ -134,16 +175,19 @@ export default function ConfigModal({ onClose }) {
</div>
)}
{/* Scan result banner */}
{scanResult !== null && (
<div className={`rounded-lg px-4 py-3 text-sm border ${
scanResult.testCount === 0
? 'bg-amber-950/50 border-amber-700 text-amber-300'
: 'bg-emerald-950/50 border-emerald-700 text-emerald-300'
}`}>
{scanResult.testCount === 0
? 'No tests found — check that the target directory contains TC_WIFI_*.ini files in subdirectories.'
: `Found ${scanResult.testCount} tests (${scanResult.completedCount} completed).`}
{/* Scanning indicator (save triggered a scan) */}
{isScanning && (
<div className="bg-blue-950/50 border border-blue-700 rounded-lg px-4 py-3 text-blue-300 text-sm flex items-center gap-2">
<span className="animate-spin inline-block"></span>
Scan in progress the table will refresh when complete.
</div>
)}
{/* Rescan indicator (rescan button used) */}
{!isScanning && isRescanning && (
<div className="bg-blue-950/50 border border-blue-700 rounded-lg px-4 py-3 text-blue-300 text-sm flex items-center gap-2">
<span className="animate-spin inline-block"></span>
Results scan in progress
</div>
)}
+1 -6
View File
@@ -4,10 +4,5 @@ import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [react(), tailwindcss()],
server: {
host: true,
proxy: {
'/api': 'http://localhost:3001',
},
},
})