Files
automaker/apps/ui/src/hooks/use-update-polling.ts
coderabbitai[bot] c9f164a1b4 📝 Add docstrings to main
Docstrings generation was requested by @amoscicki.

* https://github.com/AutoMaker-Org/automaker/pull/290#issuecomment-3694458998

The following files were modified:

* `apps/server/src/routes/updates/common.ts`
* `apps/server/src/routes/updates/index.ts`
* `apps/server/src/routes/updates/routes/check.ts`
* `apps/server/src/routes/updates/routes/info.ts`
* `apps/server/src/routes/updates/routes/pull.ts`
* `apps/ui/src/components/updates/update-notifier.tsx`
* `apps/ui/src/components/views/settings-view.tsx`
* `apps/ui/src/components/views/settings-view/updates/updates-section.tsx`
* `apps/ui/src/hooks/use-settings-migration.ts`
* `apps/ui/src/hooks/use-update-polling.ts`
* `apps/ui/src/lib/utils.ts`
* `apps/ui/src/routes/__root.tsx`
2025-12-28 05:04:14 +00:00

105 lines
3.4 KiB
TypeScript

/**
* Update Polling Hook
*
* Handles the background polling logic for checking updates.
* Separated from the store to follow single responsibility principle.
*
* This hook only manages WHEN to check, not HOW to check.
* The actual check logic lives in the updates-store.
*/
import { useEffect, useRef, useCallback } from 'react';
import { useAppStore } from '@/store/app-store';
import { useUpdatesStore } from '@/store/updates-store';
// ============================================================================
// Types
// ============================================================================
export interface UseUpdatePollingOptions {
/** Override the check function (for testing/DI) */
onCheck?: () => Promise<boolean>;
/** Override enabled state (for testing) */
enabled?: boolean;
/** Override interval in minutes (for testing) */
intervalMinutes?: number;
}
export interface UseUpdatePollingResult {
/** Whether polling is currently active */
isPollingActive: boolean;
/** Manually trigger a check */
checkNow: () => Promise<boolean>;
/** Last check timestamp */
lastChecked: Date | null;
}
// ============================================================================
// Hook
// ============================================================================
/**
* Manages periodic background checks for updates and exposes controls and status.
*
* @param options - Optional overrides for testing or dependency injection:
* - `onCheck`: override the function used to perform an update check
* - `enabled`: force polling enabled or disabled
* - `intervalMinutes`: override the polling interval in minutes
* @returns An object with polling status and controls:
* - `isPollingActive`: `true` when polling is enabled, `false` otherwise
* - `checkNow`: a function that triggers an immediate update check and returns `true` if an update was found, `false` otherwise
* - `lastChecked`: timestamp of the last performed check, or `null` if never checked
*/
export function useUpdatePolling(options: UseUpdatePollingOptions = {}): UseUpdatePollingResult {
const { autoUpdate } = useAppStore();
const { checkForUpdates, lastChecked } = useUpdatesStore();
// Allow overrides for testing
const isEnabled = options.enabled ?? autoUpdate.enabled;
const intervalMinutes = options.intervalMinutes ?? autoUpdate.checkIntervalMinutes;
// Stabilize the check function reference to prevent interval resets
const onCheckRef = useRef(options.onCheck ?? checkForUpdates);
onCheckRef.current = options.onCheck ?? checkForUpdates;
const stableOnCheck = useCallback(() => onCheckRef.current(), []);
const intervalRef = useRef<NodeJS.Timeout | null>(null);
useEffect(() => {
// Clear any existing interval
if (intervalRef.current) {
clearInterval(intervalRef.current);
intervalRef.current = null;
}
// Don't set up polling if disabled
if (!isEnabled) {
return;
}
// Check immediately on enable
stableOnCheck();
// Set up interval
const intervalMs = intervalMinutes * 60 * 1000;
intervalRef.current = setInterval(stableOnCheck, intervalMs);
return () => {
if (intervalRef.current) {
clearInterval(intervalRef.current);
intervalRef.current = null;
}
};
}, [isEnabled, intervalMinutes, stableOnCheck]);
return {
isPollingActive: isEnabled,
checkNow: stableOnCheck,
lastChecked,
};
}