mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-27 18:57:09 +00:00
71678081f0
Move the update workflow state machine and the polling driver out of the FleetView shell into two dedicated hooks under FleetView/hooks/. No behavior change. useFleetUpdateStatus owns updateStatuses + updatingNodeId + the four modal/dialog/reconnecting state slots, the synchronously-held updateStatusesRef, and every callback that touches the update workflow (fetchUpdateStatus, triggerNodeUpdate, confirmLocalUpdate, triggerUpdateAll, dismissNodeUpdate, retryNodeUpdate). The inline four- line "Check Updates" handler collapses into a single checkUpdates() callback returned from the hook. useFleetPolling is a pure side-effect hook that owns the initial-mount fetch, the paid-tier 30s overview + 120s update-status interval pair, and the 5s fast-poll accelerator gated on hasUpdatingRef. The polling hook does not know about update semantics; the consumer passes in updateStatuses and the fetch callbacks. Shell drops from 523 to 385 LOC. useState calls drop from 13 to 6, useEffect from 4 to 0, useCallback from 8 to 2, useRef from 2 to 0. Tested manually in browser: fleet view loads, masthead populates, Check Updates opens the sheet and fetches statuses, Refresh fires fetch-overview, no console errors from the refactor (existing unreachable-remote-node WebSocket failures are unrelated). Dev servers killed after validation.
46 lines
1.5 KiB
TypeScript
46 lines
1.5 KiB
TypeScript
import { useEffect, useRef } from 'react';
|
|
import type { NodeUpdateStatus } from '../types';
|
|
|
|
interface UseFleetPollingOptions {
|
|
isPaid: boolean;
|
|
fetchOverview: () => Promise<void> | void;
|
|
fetchUpdateStatus: () => Promise<void> | void;
|
|
updateStatuses: NodeUpdateStatus[];
|
|
}
|
|
|
|
export function useFleetPolling({
|
|
isPaid,
|
|
fetchOverview,
|
|
fetchUpdateStatus,
|
|
updateStatuses,
|
|
}: UseFleetPollingOptions): void {
|
|
useEffect(() => {
|
|
fetchOverview();
|
|
fetchUpdateStatus();
|
|
}, [fetchOverview, fetchUpdateStatus]);
|
|
|
|
// Paid tier: auto-refresh every 30s
|
|
useEffect(() => {
|
|
if (!isPaid) return;
|
|
const overviewInterval = setInterval(fetchOverview, 30000);
|
|
const updateInterval = setInterval(fetchUpdateStatus, 120000);
|
|
return () => { clearInterval(overviewInterval); clearInterval(updateInterval); };
|
|
}, [isPaid, fetchOverview, fetchUpdateStatus]);
|
|
|
|
// Fast poll (5s) when any node is actively updating. Uses ref to avoid interval thrashing.
|
|
const hasUpdatingRef = useRef(false);
|
|
useEffect(() => {
|
|
hasUpdatingRef.current = updateStatuses.some(s => s.updateStatus === 'updating');
|
|
}, [updateStatuses]);
|
|
|
|
useEffect(() => {
|
|
const id = setInterval(() => {
|
|
if (hasUpdatingRef.current) {
|
|
fetchUpdateStatus();
|
|
fetchOverview();
|
|
}
|
|
}, 5000);
|
|
return () => clearInterval(id);
|
|
}, [fetchUpdateStatus, fetchOverview]);
|
|
}
|