Files
clawgo/webui/src/context/AppContext.tsx

139 lines
4.4 KiB
TypeScript

import React, { createContext, useContext, useState, useEffect, useCallback } from 'react';
import { CronJob, Cfg, Session, Skill } from '../types';
interface AppContextType {
token: string;
sidebarOpen: boolean;
setSidebarOpen: (open: boolean) => void;
setToken: (token: string) => void;
isGatewayOnline: boolean;
setIsGatewayOnline: (online: boolean) => void;
cfg: Cfg;
setCfg: React.Dispatch<React.SetStateAction<Cfg>>;
cfgRaw: string;
setCfgRaw: (raw: string) => void;
nodes: string;
setNodes: (nodes: string) => void;
cron: CronJob[];
setCron: (cron: CronJob[]) => void;
skills: Skill[];
setSkills: (skills: Skill[]) => void;
sessions: Session[];
setSessions: React.Dispatch<React.SetStateAction<Session[]>>;
refreshAll: () => Promise<void>;
refreshCron: () => Promise<void>;
refreshNodes: () => Promise<void>;
refreshSkills: () => Promise<void>;
loadConfig: () => Promise<void>;
q: string;
}
const AppContext = createContext<AppContextType | undefined>(undefined);
export const AppProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const initialToken = (() => {
try {
const u = new URL(window.location.href);
return u.searchParams.get('token') || 'cg_nLnov7DPd9yqZDYPEU5pHnoa';
} catch {
return 'cg_nLnov7DPd9yqZDYPEU5pHnoa';
}
})();
const [token, setToken] = useState(initialToken);
const [sidebarOpen, setSidebarOpen] = useState(false);
const [isGatewayOnline, setIsGatewayOnline] = useState(true);
const [cfg, setCfg] = useState<Cfg>({});
const [cfgRaw, setCfgRaw] = useState('{}');
const [nodes, setNodes] = useState('[]');
const [cron, setCron] = useState<CronJob[]>([]);
const [skills, setSkills] = useState<Skill[]>([]);
const [sessions, setSessions] = useState<Session[]>([{ key: 'webui:default', title: 'Default' }]);
const q = token ? `?token=${encodeURIComponent(token)}` : '';
const loadConfig = useCallback(async () => {
try {
const r = await fetch(`/webui/api/config${q}`);
if (!r.ok) throw new Error('Failed to load config');
const txt = await r.text();
setCfgRaw(txt);
try { setCfg(JSON.parse(txt)); } catch { setCfg({}); }
setIsGatewayOnline(true);
} catch (e) {
setIsGatewayOnline(false);
console.error(e);
}
}, [q]);
const refreshNodes = useCallback(async () => {
try {
const r = await fetch(`/webui/api/nodes${q}`);
if (!r.ok) throw new Error('Failed to load nodes');
const j = await r.json();
setNodes(JSON.stringify(j.nodes || [], null, 2));
setIsGatewayOnline(true);
} catch (e) {
setIsGatewayOnline(false);
console.error(e);
}
}, [q]);
const refreshCron = useCallback(async () => {
try {
const r = await fetch(`/webui/api/cron${q}`);
if (!r.ok) throw new Error('Failed to load cron');
const j = await r.json();
setCron(Array.isArray(j.jobs) ? j.jobs : []);
setIsGatewayOnline(true);
} catch (e) {
setIsGatewayOnline(false);
console.error(e);
}
}, [q]);
const refreshSkills = useCallback(async () => {
try {
const r = await fetch(`/webui/api/skills${q}`);
if (!r.ok) throw new Error('Failed to load skills');
const j = await r.json();
setSkills(Array.isArray(j.skills) ? j.skills : []);
setIsGatewayOnline(true);
} catch (e) {
setIsGatewayOnline(false);
console.error(e);
}
}, [q]);
const refreshAll = useCallback(async () => {
await Promise.all([loadConfig(), refreshCron(), refreshNodes(), refreshSkills()]);
}, [loadConfig, refreshCron, refreshNodes, refreshSkills]);
useEffect(() => {
refreshAll();
const interval = setInterval(() => {
refreshCron();
refreshNodes();
refreshSkills();
}, 10000);
return () => clearInterval(interval);
}, [token, refreshAll, refreshCron, refreshNodes, refreshSkills]);
return (
<AppContext.Provider value={{
token, setToken, sidebarOpen, setSidebarOpen, isGatewayOnline, setIsGatewayOnline,
cfg, setCfg, cfgRaw, setCfgRaw, nodes, setNodes,
cron, setCron, skills, setSkills,
sessions, setSessions,
refreshAll, refreshCron, refreshNodes, refreshSkills, loadConfig, q
}}>
{children}
</AppContext.Provider>
);
};
export const useAppContext = () => {
const context = useContext(AppContext);
if (!context) throw new Error('useAppContext must be used within an AppProvider');
return context;
};