diff --git a/src/app/(dashboard)/dashboard/memory/hooks/useEngineStatus.ts b/src/app/(dashboard)/dashboard/memory/hooks/useEngineStatus.ts index 37a9dddb7a..5480d80a0c 100644 --- a/src/app/(dashboard)/dashboard/memory/hooks/useEngineStatus.ts +++ b/src/app/(dashboard)/dashboard/memory/hooks/useEngineStatus.ts @@ -1,28 +1,58 @@ "use client"; -import useSWR from "swr"; +import { useCallback, useEffect, useRef, useState } from "react"; import type { MemoryEngineStatus } from "@/shared/schemas/memory"; -const fetcher = (url: string) => fetch(url).then((res) => res.json()); - export interface UseEngineStatusResult { status: MemoryEngineStatus | null; isLoading: boolean; isError: boolean; - mutate: () => void; + mutate: () => Promise; } -export function useEngineStatus(): UseEngineStatusResult { - const { data, error, isLoading, mutate } = useSWR( - "/api/memory/engine-status", - fetcher, - { refreshInterval: 5000 }, - ); +/** + * Lightweight engine-status fetcher with periodic polling. + * Avoids the swr dependency (not installed in this project) while keeping a + * compatible mutate()/loading/error surface for callers. + */ +export function useEngineStatus(refreshIntervalMs = 5000): UseEngineStatusResult { + const [status, setStatus] = useState(null); + const [isLoading, setIsLoading] = useState(true); + const [isError, setIsError] = useState(false); + const mounted = useRef(true); - return { - status: data ?? null, - isLoading, - isError: Boolean(error), - mutate, - }; + const fetchOnce = useCallback(async (): Promise => { + try { + const res = await fetch("/api/memory/engine-status"); + if (!res.ok) throw new Error(`status_${res.status}`); + const data = (await res.json()) as MemoryEngineStatus; + if (mounted.current) { + setStatus(data); + setIsError(false); + } + } catch { + if (mounted.current) setIsError(true); + } finally { + if (mounted.current) setIsLoading(false); + } + }, []); + + useEffect(() => { + mounted.current = true; + void fetchOnce(); + if (!refreshIntervalMs || refreshIntervalMs <= 0) { + return () => { + mounted.current = false; + }; + } + const id = setInterval(() => { + void fetchOnce(); + }, refreshIntervalMs); + return () => { + mounted.current = false; + clearInterval(id); + }; + }, [fetchOnce, refreshIntervalMs]); + + return { status, isLoading, isError, mutate: fetchOnce }; } diff --git a/src/app/(dashboard)/dashboard/memory/hooks/useMemorySettings.ts b/src/app/(dashboard)/dashboard/memory/hooks/useMemorySettings.ts index 49b5f32a17..ae50f246fa 100644 --- a/src/app/(dashboard)/dashboard/memory/hooks/useMemorySettings.ts +++ b/src/app/(dashboard)/dashboard/memory/hooks/useMemorySettings.ts @@ -1,48 +1,68 @@ "use client"; -import useSWR from "swr"; +import { useCallback, useEffect, useRef, useState } from "react"; import type { MemorySettingsExtended } from "@/shared/schemas/memory"; -const fetcher = (url: string) => fetch(url).then((res) => res.json()); - export interface UseMemorySettingsResult { settings: MemorySettingsExtended | null; isLoading: boolean; isError: boolean; - mutate: () => void; + mutate: () => Promise; save: (updates: Partial) => Promise; } +/** + * Lightweight settings fetcher + saver. + * Avoids the swr dependency (not installed in this project) while keeping a + * compatible mutate()/save() surface for callers. + */ export function useMemorySettings(): UseMemorySettingsResult { - const { data, error, isLoading, mutate } = useSWR( - "/api/settings/memory", - fetcher, + const [settings, setSettings] = useState(null); + const [isLoading, setIsLoading] = useState(true); + const [isError, setIsError] = useState(false); + const mounted = useRef(true); + + const fetchOnce = useCallback(async (): Promise => { + try { + const res = await fetch("/api/settings/memory"); + if (!res.ok) throw new Error(`status_${res.status}`); + const data = (await res.json()) as MemorySettingsExtended; + if (mounted.current) { + setSettings(data); + setIsError(false); + } + } catch { + if (mounted.current) setIsError(true); + } finally { + if (mounted.current) setIsLoading(false); + } + }, []); + + useEffect(() => { + mounted.current = true; + void fetchOnce(); + return () => { + mounted.current = false; + }; + }, [fetchOnce]); + + const save = useCallback( + async (updates: Partial): Promise => { + try { + const res = await fetch("/api/settings/memory", { + method: "PUT", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(updates), + }); + if (!res.ok) return false; + await fetchOnce(); + return true; + } catch { + return false; + } + }, + [fetchOnce] ); - const save = async (updates: Partial): Promise => { - try { - const current = data ?? {}; - const next = { ...current, ...updates }; - const res = await fetch("/api/settings/memory", { - method: "PUT", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify(next), - }); - if (res.ok) { - await mutate(); - return true; - } - return false; - } catch { - return false; - } - }; - - return { - settings: data ?? null, - isLoading, - isError: Boolean(error), - mutate, - save, - }; + return { settings, isLoading, isError, mutate: fetchOnce, save }; }