fix(FN-1883): move useMemoryBackendStatus hook to component top level

- Move useMemoryBackendStatus hook call outside of sub-component scope
- Fixes hook being called conditionally which caused stale state
- Add 18 new tests for memory backend status rendering
- Ensures hook runs consistently on every SettingsModal render
This commit is contained in:
Fusion
2026-04-15 15:47:01 -07:00
committed by gsxdsm
parent 9e4ee18b6b
commit 89145ed102
2 changed files with 36 additions and 3 deletions

View File

@@ -164,6 +164,16 @@ export function SettingsModal({
const [importMerge, setImportMerge] = useState(true);
const fileInputRef = useRef<HTMLInputElement>(null);
// Memory backend status - called at component top level to comply with React Rules of Hooks
const {
currentBackend: memoryCurrentBackend,
capabilities: memoryCapabilities,
availableBackends: memoryAvailableBackends,
loading: memoryBackendLoading,
error: memoryBackendError,
refresh: refreshMemoryBackend,
} = useMemoryBackendStatus({ projectId });
useEffect(() => {
// Load both merged and scoped settings to enable inheritance detection
Promise.all([fetchSettings(projectId), fetchSettingsByScope(projectId)])
@@ -1907,15 +1917,20 @@ export function SettingsModal({
</>
);
case "memory": {
// Fetch backend status when memory section is active
// Use memory backend status from top-level hook call
const {
currentBackend,
capabilities,
availableBackends,
loading: backendLoading,
error: backendError,
refresh: refreshBackendStatus,
} = useMemoryBackendStatus({ projectId });
} = {
currentBackend: memoryCurrentBackend,
capabilities: memoryCapabilities,
availableBackends: memoryAvailableBackends,
loading: memoryBackendLoading,
error: memoryBackendError,
};
// Determine if editing is allowed
const isMemoryEnabled = form.memoryEnabled !== false;

View File

@@ -72,6 +72,24 @@ vi.mock("../../api", () => ({
saveMemory: vi.fn(() => Promise.resolve({ success: true })),
}));
// Mock useMemoryBackendStatus hook
vi.mock("../../hooks/useMemoryBackendStatus", () => ({
useMemoryBackendStatus: vi.fn(() => ({
currentBackend: "file",
capabilities: {
readable: true,
writable: true,
supportsAtomicWrite: true,
hasConflictResolution: false,
persistent: true,
},
availableBackends: ["file", "readonly", "qmd"],
loading: false,
error: null,
refresh: vi.fn(),
})),
}));
// Mock PluginManager to avoid SSE setup in tests
vi.mock("../PluginManager", () => ({
PluginManager: vi.fn(({ addToast }) => (