(fix) module refresh bug..

This commit is contained in:
2026-09-08 15:12:13 +09:00
parent 5aef38a99d
commit 189ca80343
2 changed files with 102 additions and 26 deletions
@@ -105,6 +105,9 @@ export function useWorkspaceModuleList({
const moduleInputsRef = useRef({ curriculumModules, applyModuleParameterOverrides })
const loadSequenceRef = useRef(0)
const moduleLoadInFlightRef = useRef(false)
const queuedModuleLoadRef = useRef<(() => void) | null>(null)
const workspaceScopeKey = remoteWorkspace ? `remote:${remoteWorkspaceTargetKey}` : `local:${clonePathPreview}`
const previousWorkspaceScopeRef = useRef(workspaceScopeKey)
const pendingModuleStatesRef = useRef(new Map<string, { state: ModuleRow['state']; expiresAt: number }>())
const moduleStateKey = (module: ModuleRow): string => module.folderName ?? module.name
@@ -173,7 +176,10 @@ export function useWorkspaceModuleList({
const loadAvailableModules = useCallback(async ({ silent = false }: LoadAvailableModulesOptions = {}): Promise<void> => {
// Remote probes open an SSH session. Do not let polling overlap a slow
// probe, otherwise every response becomes stale and loading never settles.
if (moduleLoadInFlightRef.current) return
if (moduleLoadInFlightRef.current) {
queuedModuleLoadRef.current = () => { void loadAvailableModules({ silent }) }
return
}
moduleLoadInFlightRef.current = true
const requestSequence = ++loadSequenceRef.current
if (!silent) setModulesLoading(true)
@@ -212,6 +218,9 @@ export function useWorkspaceModuleList({
} finally {
moduleLoadInFlightRef.current = false
if (!silent && requestSequence === loadSequenceRef.current) setModulesLoading(false)
const queuedLoad = queuedModuleLoadRef.current
queuedModuleLoadRef.current = null
queuedLoad?.()
}
}, [
applyPendingModuleStates,
@@ -223,24 +232,38 @@ export function useWorkspaceModuleList({
])
useEffect(() => {
// A response for an earlier module set must not replace newly added rows.
++loadSequenceRef.current
const sameWorkspace = previousWorkspaceScopeRef.current === workspaceScopeKey
previousWorkspaceScopeRef.current = workspaceScopeKey
if (!sameWorkspace) pendingModuleStatesRef.current.clear()
const cachedModules = readRemoteModuleCache(moduleCacheKey)
if (cachedModules) {
const modules = applyPendingModuleStates(
moduleInputsRef.current.applyModuleParameterOverrides(cachedModules).sort(compareModulePriority),
)
setAvailableModules(modules)
setModuleListError(null)
setModulesLoading(false)
if (skipInitialModuleLoad) return
}
setAvailableModules((current) => {
const previous = new Map((sameWorkspace && current.length ? current : cachedModules ?? [])
.map((module) => [module.folderName ?? module.name, module]))
const modules = makeUninstalledModuleRows(moduleInputsRef.current.curriculumModules).map((module) => {
const existing = previous.get(module.folderName ?? module.name)
return existing ? {
...module,
state: existing.state,
workspacePath: existing.workspacePath,
parameters: existing.parameters,
cpu: existing.cpu,
memory: existing.memory,
runtime: existing.runtime,
} : module
})
return applyPendingModuleStates(moduleInputsRef.current.applyModuleParameterOverrides(modules))
})
setModuleListError(null)
setModulesLoading(false)
if (!(cachedModules && skipInitialModuleLoad)) void loadAvailableModules()
if (!cachedModules) {
setAvailableModules(makeUninstalledModuleRows(moduleInputsRef.current.curriculumModules))
setModuleListError(null)
return () => {
++loadSequenceRef.current
queuedModuleLoadRef.current = null
}
void loadAvailableModules()
}, [applyPendingModuleStates, loadAvailableModules, moduleCacheKey, remoteWorkspaceTargetKey, skipInitialModuleLoad])
}, [applyPendingModuleStates, loadAvailableModules, moduleCacheKey, skipInitialModuleLoad, workspaceScopeKey])
useEffect(() => {
if (!pollingActive) return