feat: live status polling in RecorderRow, immediate refresh on mount
This commit is contained in:
parent
bb508d3256
commit
665ab5238d
1 changed files with 46 additions and 3 deletions
|
|
@ -219,6 +219,7 @@ function Recorders({ navigate, onNew }) {
|
|||
}, []);
|
||||
|
||||
React.useEffect(() => {
|
||||
refresh();
|
||||
const id = setInterval(refresh, 10000);
|
||||
return () => clearInterval(id);
|
||||
}, []);
|
||||
|
|
@ -261,10 +262,42 @@ function RecorderRow({ recorder: initialRecorder, onRefresh }) {
|
|||
const [recorder, setRecorder] = React.useState(initialRecorder);
|
||||
const [pending, setPending] = React.useState(false);
|
||||
const [err, setErr] = React.useState(null);
|
||||
const [liveStatus, setLiveStatus] = React.useState(null);
|
||||
const isRec = recorder.status === 'recording';
|
||||
|
||||
React.useEffect(() => { setRecorder(initialRecorder); }, [initialRecorder.id, initialRecorder.status]);
|
||||
|
||||
// Poll the status endpoint every 3s while recording for live feedback.
|
||||
React.useEffect(() => {
|
||||
if (!isRec) { setLiveStatus(null); return; }
|
||||
const poll = () => {
|
||||
window.ZAMPP_API.fetch('/recorders/' + recorder.id + '/status')
|
||||
.then(s => setLiveStatus(s))
|
||||
.catch(() => {});
|
||||
};
|
||||
poll();
|
||||
const id = setInterval(poll, 3000);
|
||||
return () => clearInterval(id);
|
||||
}, [isRec, recorder.id]);
|
||||
|
||||
const displayElapsed = React.useMemo(() => {
|
||||
if (liveStatus && liveStatus.duration != null) {
|
||||
const d = Math.max(0, liveStatus.duration);
|
||||
return String(Math.floor(d / 3600)).padStart(2, '0') + ':' +
|
||||
String(Math.floor((d % 3600) / 60)).padStart(2, '0') + ':' +
|
||||
String(d % 60).padStart(2, '0');
|
||||
}
|
||||
return recorder.elapsed;
|
||||
}, [liveStatus, recorder.elapsed]);
|
||||
|
||||
const displaySignal = liveStatus
|
||||
? (liveStatus.signal || '—')
|
||||
: (isRec ? 'connecting…' : '—');
|
||||
|
||||
const signalColor = displaySignal === 'receiving' ? 'var(--success)'
|
||||
: displaySignal === 'stopped' ? 'var(--danger)'
|
||||
: 'var(--text-3)';
|
||||
|
||||
const toggle = () => {
|
||||
if (pending) return;
|
||||
const action = isRec ? 'stop' : 'start';
|
||||
|
|
@ -297,16 +330,25 @@ function RecorderRow({ recorder: initialRecorder, onRefresh }) {
|
|||
<span>{recorder.res}</span>
|
||||
</div>
|
||||
{err && <div style={{ marginTop: 4, fontSize: 11, color: 'var(--danger)' }}>{err}</div>}
|
||||
{liveStatus?.lastError && isRec && (
|
||||
<div style={{ marginTop: 4, fontSize: 11, color: 'var(--danger)' }}>{liveStatus.lastError}</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="recorder-stats">
|
||||
<div className="recorder-stat">
|
||||
<div className="stat-label">Elapsed</div>
|
||||
<div className="stat-val mono">{recorder.elapsed}</div>
|
||||
<div className="stat-val mono">{displayElapsed}</div>
|
||||
</div>
|
||||
<div className="recorder-stat">
|
||||
<div className="stat-label">Status</div>
|
||||
<div className="stat-val"><StatusDot status={recorder.status} /></div>
|
||||
<div className="stat-label">Signal</div>
|
||||
<div className="stat-val" style={{ fontSize: 11, color: signalColor }}>{displaySignal}</div>
|
||||
</div>
|
||||
{liveStatus?.currentFps != null && (
|
||||
<div className="recorder-stat">
|
||||
<div className="stat-label">FPS</div>
|
||||
<div className="stat-val mono">{Number(liveStatus.currentFps).toFixed(1)}</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="recorder-actions">
|
||||
{isRec
|
||||
|
|
@ -405,6 +447,7 @@ function Monitors({ navigate }) {
|
|||
})
|
||||
.catch(() => {});
|
||||
};
|
||||
refresh();
|
||||
const id = setInterval(refresh, 5000);
|
||||
return () => clearInterval(id);
|
||||
}, []);
|
||||
|
|
|
|||
Loading…
Reference in a new issue