Files
fusion/packages/dashboard/app/hooks/useAppSettings.ts
gsxdsm 7becb33972 feat(FN-1203): extract App orchestration into focused hooks
- Extract modal manager, app settings, deep-link handling, favorites, and auth onboarding into dedicated hooks
- Rewire App.tsx to consume the new hooks and reduce component-level state/effect complexity
- Preserve favorite-toggle error toast behavior in the updated favorites wiring
- Add hook-level test coverage for modal manager, app settings, deep links, favorites, and auth onboarding flows
2026-04-08 05:53:24 -07:00

101 lines
2.8 KiB
TypeScript

import { useCallback, useEffect, useState } from "react";
import { fetchConfig, fetchSettings, updateSettings } from "../api";
/**
* Settings state and actions consumed by the dashboard App shell.
*/
export interface UseAppSettingsResult {
maxConcurrent: number;
rootDir: string;
autoMerge: boolean;
globalPaused: boolean;
enginePaused: boolean;
taskStuckTimeoutMs: number | undefined;
githubTokenConfigured: boolean;
toggleAutoMerge: () => Promise<void>;
toggleGlobalPause: () => Promise<void>;
toggleEnginePause: () => Promise<void>;
}
/**
* Loads per-project dashboard settings and exposes optimistic toggle handlers.
*/
export function useAppSettings(projectId?: string): UseAppSettingsResult {
const [maxConcurrent, setMaxConcurrent] = useState(2);
const [rootDir, setRootDir] = useState<string>(".");
const [autoMerge, setAutoMerge] = useState(true);
const [globalPaused, setGlobalPaused] = useState(false);
const [enginePaused, setEnginePaused] = useState(false);
const [taskStuckTimeoutMs, setTaskStuckTimeoutMs] = useState<number | undefined>(undefined);
const [githubTokenConfigured, setGithubTokenConfigured] = useState(false);
useEffect(() => {
fetchConfig(projectId)
.then((cfg) => {
setMaxConcurrent(cfg.maxConcurrent);
setRootDir(cfg.rootDir);
})
.catch(() => {
// Keep defaults on fetch failure.
});
fetchSettings(projectId)
.then((settings) => {
setAutoMerge(Boolean(settings.autoMerge));
setGlobalPaused(Boolean(settings.globalPause));
setEnginePaused(Boolean(settings.enginePaused));
setGithubTokenConfigured(Boolean(settings.githubTokenConfigured));
setTaskStuckTimeoutMs(settings.taskStuckTimeoutMs);
})
.catch(() => {
// Keep defaults on fetch failure.
});
}, [projectId]);
const toggleAutoMerge = useCallback(async () => {
const next = !autoMerge;
setAutoMerge(next);
try {
await updateSettings({ autoMerge: next }, projectId);
} catch {
setAutoMerge(!next);
}
}, [autoMerge, projectId]);
const toggleGlobalPause = useCallback(async () => {
const next = !globalPaused;
setGlobalPaused(next);
try {
await updateSettings({ globalPause: next }, projectId);
} catch {
setGlobalPaused(!next);
}
}, [globalPaused, projectId]);
const toggleEnginePause = useCallback(async () => {
const next = !enginePaused;
setEnginePaused(next);
try {
await updateSettings({ enginePaused: next }, projectId);
} catch {
setEnginePaused(!next);
}
}, [enginePaused, projectId]);
return {
maxConcurrent,
rootDir,
autoMerge,
globalPaused,
enginePaused,
taskStuckTimeoutMs,
githubTokenConfigured,
toggleAutoMerge,
toggleGlobalPause,
toggleEnginePause,
};
}