"use client"; import React, { ReactNode, useCallback, useEffect, useState } from "react"; import { del, get, post } from "../../lib/api"; export interface Settings { [key: string]: any; } export interface Dataset { [path: string]: any; } export interface DatasetsConfig { [datasetName: string]: Dataset; } export interface QueueConfig { maxConcurrent?: number; maxRetries?: number; [key: string]: any; } export interface WatcherConfig { enabled?: boolean; [key: string]: any; } export interface AppContextType { // Data settings: Settings | null; datasetsConfig: DatasetsConfig | null; queueConfig: QueueConfig | null; watcherConfig: WatcherConfig | null; datasets: string[] | null; // Loading states isLoading: boolean; isInitialized: boolean; // Errors error: Error | null; // Mutation functions updateSetting: (key: string, value: any) => Promise; deleteSetting: (key: string) => Promise; updateDatasets: (datasets: DatasetsConfig) => Promise; updateQueueConfig: (config: QueueConfig) => Promise; updateWatcherConfig: (config: WatcherConfig) => Promise; // Refresh functions refreshSettings: () => Promise; refreshDatasets: () => Promise; refreshAll: () => Promise; } const AppContext = React.createContext(undefined); export function AppProvider({ children }: { children: ReactNode }) { const [settings, setSettings] = useState(null); const [datasetsConfig, setDatasetsConfig] = useState( null ); const [queueConfig, setQueueConfig] = useState(null); const [watcherConfig, setWatcherConfig] = useState( null ); const [datasets, setDatasets] = useState(null); const [isLoading, setIsLoading] = useState(true); const [isInitialized, setIsInitialized] = useState(false); const [error, setError] = useState(null); // Load all initial data const initializeData = useCallback(async () => { try { setIsLoading(true); setError(null); // Load settings const settingsData = await get("/config/settings"); setSettings(settingsData || {}); // Extract specific configs from settings if (settingsData) { const queue = settingsData.queue || {}; const watcher = settingsData.watcher || {}; const datasetsData = settingsData.datasets || {}; setQueueConfig(queue); setWatcherConfig(watcher); setDatasetsConfig(datasetsData); } // Load datasets list const datasetsList = await get("/files/all-datasets"); setDatasets(datasetsList || []); setIsInitialized(true); } catch (err) { const error = err instanceof Error ? err : new Error(String(err)); setError(error); console.error("Failed to initialize app context:", error); } finally { setIsLoading(false); } }, []); // Initial load useEffect(() => { initializeData(); }, [initializeData]); // Listen for WebSocket events useEffect(() => { const handleSettingsUpdate = () => { initializeData(); }; const handleTaskUpdate = () => { // Refetch datasets in case new ones were created initializeData(); }; const handleFileUpdate = () => { // Refetch datasets in case new ones were created initializeData(); }; window.addEventListener( "settingsUpdate", handleSettingsUpdate as EventListener ); window.addEventListener("taskUpdate", handleTaskUpdate as EventListener); window.addEventListener("fileUpdate", handleFileUpdate as EventListener); return () => { window.removeEventListener( "settingsUpdate", handleSettingsUpdate as EventListener ); window.removeEventListener( "taskUpdate", handleTaskUpdate as EventListener ); window.removeEventListener( "fileUpdate", handleFileUpdate as EventListener ); }; }, [initializeData]); // Mutation functions const updateSetting = useCallback( async (key: string, value: any) => { try { await post("/config/settings", { [key]: value }); setSettings((prev) => prev ? { ...prev, [key]: value } : { [key]: value } ); await initializeData(); } catch (err) { const error = err instanceof Error ? err : new Error(String(err)); setError(error); throw error; } }, [initializeData] ); const deleteSetting = useCallback( async (key: string) => { try { await del(`/config/settings/${key}`); setSettings((prev) => { if (!prev) return null; const updated = { ...prev }; delete updated[key]; return updated; }); await initializeData(); } catch (err) { const error = err instanceof Error ? err : new Error(String(err)); setError(error); throw error; } }, [initializeData] ); const updateDatasets = useCallback( async (datasetsData: DatasetsConfig) => { try { setDatasetsConfig(datasetsData); await updateSetting("datasets", datasetsData); } catch (err) { const error = err instanceof Error ? err : new Error(String(err)); setError(error); throw error; } }, [updateSetting] ); const updateQueueConfig = useCallback( async (config: QueueConfig) => { try { setQueueConfig(config); await updateSetting("queue", config); } catch (err) { const error = err instanceof Error ? err : new Error(String(err)); setError(error); throw error; } }, [updateSetting] ); const updateWatcherConfig = useCallback( async (config: WatcherConfig) => { try { setWatcherConfig(config); await updateSetting("watcher", config); } catch (err) { const error = err instanceof Error ? err : new Error(String(err)); setError(error); throw error; } }, [updateSetting] ); const refreshSettings = useCallback(async () => { try { const settingsData = await get("/config/settings"); setSettings(settingsData || {}); if (settingsData) { setQueueConfig(settingsData.queue || {}); setWatcherConfig(settingsData.watcher || {}); setDatasetsConfig(settingsData.datasets || {}); } } catch (err) { const error = err instanceof Error ? err : new Error(String(err)); setError(error); throw error; } }, []); const refreshDatasets = useCallback(async () => { try { const datasetsList = await get("/files/all-datasets"); setDatasets(datasetsList || []); } catch (err) { const error = err instanceof Error ? err : new Error(String(err)); setError(error); throw error; } }, []); const refreshAll = useCallback(async () => { await initializeData(); }, [initializeData]); const value: AppContextType = { settings, datasetsConfig, queueConfig, watcherConfig, datasets, isLoading, isInitialized, error, updateSetting, deleteSetting, updateDatasets, updateQueueConfig, updateWatcherConfig, refreshSettings, refreshDatasets, refreshAll }; return {children}; } export function useAppContext() { const context = React.useContext(AppContext); if (context === undefined) { throw new Error("useAppContext must be used within an AppProvider"); } return context; }