mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-02 23:19:33 +00:00
3f2ff47c94
EditorLayout owned the stack-image-update state plus a 5-minute polling interval as part of a 30-line useEffect that already juggled six other concerns (selected file, active view, stacks refresh, auto-update settings, git-source pending, …). The image- update slice has clean boundaries: it depends on activeNode.id, mutates one state object, and is otherwise unrelated to the rest of the effect. Move it into a dedicated hook at frontend/src/hooks/useImageUpdates.ts. The hook owns the stackUpdates state, runs an initial fetch on activeNode.id change, schedules the 5-minute poll, and exposes a refresh() callback for the four manual-trigger sites (deploy success, image-update action, manual registry-refresh poll). The hook destructure aliases refresh to fetchImageUpdates so existing call sites in EditorLayout don't need to be renamed. This is the first slice of audit finding 1.6 (EditorLayout 3129-line refactor); the next slice is useFleetNotifications.
45 lines
1.5 KiB
TypeScript
45 lines
1.5 KiB
TypeScript
import { useState, useEffect, useCallback, useRef } from 'react';
|
|
import { apiFetch } from '@/lib/api';
|
|
|
|
const IMAGE_UPDATE_POLL_MS = 5 * 60 * 1000;
|
|
|
|
/**
|
|
* Owns the stack-image-update state and its 5-minute background poll.
|
|
* Re-fetches whenever `activeNodeId` changes; consumers can also call
|
|
* `refresh()` to force a refetch (e.g. after a deploy or a manual
|
|
* registry-check trigger).
|
|
*
|
|
* Extracted from EditorLayout so the polling lifecycle and its state
|
|
* live next to each other instead of being spread across a 3000-line
|
|
* component. The dependency on `apiFetch` keeps the call routed
|
|
* through the active-node header just like before.
|
|
*/
|
|
export function useImageUpdates(activeNodeId: number | undefined) {
|
|
const [stackUpdates, setStackUpdates] = useState<Record<string, boolean>>({});
|
|
|
|
const refresh = useCallback(async () => {
|
|
try {
|
|
const res = await apiFetch('/image-updates');
|
|
if (res.ok) {
|
|
const data = await res.json() as Record<string, boolean>;
|
|
setStackUpdates(data);
|
|
}
|
|
} catch (e: unknown) {
|
|
console.error('[ImageUpdates] fetch failed:', e);
|
|
}
|
|
}, []);
|
|
|
|
// Pin the interval to the latest closure without retriggering it on
|
|
// every render the way putting `refresh` into the deps array would.
|
|
const refreshRef = useRef(refresh);
|
|
refreshRef.current = refresh;
|
|
|
|
useEffect(() => {
|
|
void refreshRef.current();
|
|
const id = setInterval(() => { void refreshRef.current(); }, IMAGE_UPDATE_POLL_MS);
|
|
return () => clearInterval(id);
|
|
}, [activeNodeId]);
|
|
|
|
return { stackUpdates, refresh };
|
|
}
|