feat: track processing start-times + global needs-input set for activity monitor
This commit is contained in:
parent
7d9d4fa2bc
commit
9c2ac65635
1 changed files with 49 additions and 0 deletions
|
|
@ -3,6 +3,10 @@ import { useCallback, useState } from 'react';
|
||||||
export function useSessionProtection() {
|
export function useSessionProtection() {
|
||||||
const [activeSessions, setActiveSessions] = useState<Set<string>>(new Set());
|
const [activeSessions, setActiveSessions] = useState<Set<string>>(new Set());
|
||||||
const [processingSessions, setProcessingSessions] = useState<Set<string>>(new Set());
|
const [processingSessions, setProcessingSessions] = useState<Set<string>>(new Set());
|
||||||
|
// sessionId -> epoch ms when processing began (for the live elapsed timer)
|
||||||
|
const [processingStartTimes, setProcessingStartTimes] = useState<Map<string, number>>(new Map());
|
||||||
|
// sessions waiting on the user (permission / AskUserQuestion pending)
|
||||||
|
const [needsInputSessions, setNeedsInputSessions] = useState<Set<string>>(new Set());
|
||||||
|
|
||||||
const markSessionAsActive = useCallback((sessionId?: string | null) => {
|
const markSessionAsActive = useCallback((sessionId?: string | null) => {
|
||||||
if (!sessionId) {
|
if (!sessionId) {
|
||||||
|
|
@ -30,6 +34,16 @@ export function useSessionProtection() {
|
||||||
}
|
}
|
||||||
|
|
||||||
setProcessingSessions((prev) => new Set([...prev, sessionId]));
|
setProcessingSessions((prev) => new Set([...prev, sessionId]));
|
||||||
|
setProcessingStartTimes((prev) => {
|
||||||
|
// Preserve an existing start time so the elapsed timer doesn't reset on
|
||||||
|
// repeated marks for the same run.
|
||||||
|
if (prev.has(sessionId)) {
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
const next = new Map(prev);
|
||||||
|
next.set(sessionId, Date.now());
|
||||||
|
return next;
|
||||||
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const markSessionAsNotProcessing = useCallback((sessionId?: string | null) => {
|
const markSessionAsNotProcessing = useCallback((sessionId?: string | null) => {
|
||||||
|
|
@ -42,14 +56,49 @@ export function useSessionProtection() {
|
||||||
next.delete(sessionId);
|
next.delete(sessionId);
|
||||||
return next;
|
return next;
|
||||||
});
|
});
|
||||||
|
setProcessingStartTimes((prev) => {
|
||||||
|
if (!prev.has(sessionId)) {
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
const next = new Map(prev);
|
||||||
|
next.delete(sessionId);
|
||||||
|
return next;
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const markSessionAsNeedsInput = useCallback((sessionId?: string | null) => {
|
||||||
|
if (!sessionId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setNeedsInputSessions((prev) => new Set([...prev, sessionId]));
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const clearSessionNeedsInput = useCallback((sessionId?: string | null) => {
|
||||||
|
if (!sessionId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setNeedsInputSessions((prev) => {
|
||||||
|
if (!prev.has(sessionId)) {
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
const next = new Set(prev);
|
||||||
|
next.delete(sessionId);
|
||||||
|
return next;
|
||||||
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
activeSessions,
|
activeSessions,
|
||||||
processingSessions,
|
processingSessions,
|
||||||
|
processingStartTimes,
|
||||||
|
needsInputSessions,
|
||||||
markSessionAsActive,
|
markSessionAsActive,
|
||||||
markSessionAsInactive,
|
markSessionAsInactive,
|
||||||
markSessionAsProcessing,
|
markSessionAsProcessing,
|
||||||
markSessionAsNotProcessing,
|
markSessionAsNotProcessing,
|
||||||
|
markSessionAsNeedsInput,
|
||||||
|
clearSessionNeedsInput,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue