mirror of
https://github.com/YspCoder/clawgo.git
synced 2026-04-14 17:07:29 +08:00
fix webui i18n
This commit is contained in:
@@ -18,6 +18,8 @@ interface AppContextType {
|
||||
setCron: (cron: CronJob[]) => void;
|
||||
skills: Skill[];
|
||||
setSkills: (skills: Skill[]) => void;
|
||||
clawhubInstalled: boolean;
|
||||
clawhubPath: string;
|
||||
sessions: Session[];
|
||||
setSessions: React.Dispatch<React.SetStateAction<Session[]>>;
|
||||
refreshAll: () => Promise<void>;
|
||||
@@ -53,6 +55,8 @@ export const AppProvider: React.FC<{ children: React.ReactNode }> = ({ children
|
||||
const [nodes, setNodes] = useState('[]');
|
||||
const [cron, setCron] = useState<CronJob[]>([]);
|
||||
const [skills, setSkills] = useState<Skill[]>([]);
|
||||
const [clawhubInstalled, setClawhubInstalled] = useState(false);
|
||||
const [clawhubPath, setClawhubPath] = useState('');
|
||||
const [sessions, setSessions] = useState<Session[]>([{ key: 'main', title: 'main' }]);
|
||||
const [gatewayVersion, setGatewayVersion] = useState('unknown');
|
||||
const [webuiVersion, setWebuiVersion] = useState('unknown');
|
||||
@@ -121,6 +125,8 @@ export const AppProvider: React.FC<{ children: React.ReactNode }> = ({ children
|
||||
if (!r.ok) throw new Error('Failed to load skills');
|
||||
const j = await r.json();
|
||||
setSkills(Array.isArray(j.skills) ? j.skills : []);
|
||||
setClawhubInstalled(!!j.clawhub_installed);
|
||||
setClawhubPath(typeof j.clawhub_path === 'string' ? j.clawhub_path : '');
|
||||
setIsGatewayOnline(true);
|
||||
} catch (e) {
|
||||
setIsGatewayOnline(false);
|
||||
@@ -174,7 +180,7 @@ export const AppProvider: React.FC<{ children: React.ReactNode }> = ({ children
|
||||
<AppContext.Provider value={{
|
||||
token, setToken, sidebarOpen, setSidebarOpen, isGatewayOnline, setIsGatewayOnline,
|
||||
cfg, setCfg, cfgRaw, setCfgRaw, nodes, setNodes,
|
||||
cron, setCron, skills, setSkills,
|
||||
cron, setCron, skills, setSkills, clawhubInstalled, clawhubPath,
|
||||
sessions, setSessions,
|
||||
refreshAll, refreshCron, refreshNodes, refreshSkills, refreshSessions, refreshVersion, loadConfig,
|
||||
gatewayVersion, webuiVersion, hotReloadFields, hotReloadFieldDetails, q
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React, { createContext, useContext, useMemo, useState } from 'react';
|
||||
import { AnimatePresence, motion } from 'motion/react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { GlobalDialog, DialogOptions } from '../components/GlobalDialog';
|
||||
|
||||
type UIContextType = {
|
||||
@@ -15,15 +16,16 @@ type UIContextType = {
|
||||
const UIContext = createContext<UIContextType | undefined>(undefined);
|
||||
|
||||
export const UIProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
||||
const { t } = useTranslation();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [loadingText, setLoadingText] = useState('Loading...');
|
||||
const [loadingText, setLoadingText] = useState(t('loading'));
|
||||
const [dialog, setDialog] = useState<null | { kind: 'notice' | 'confirm'; options: DialogOptions; resolve: (v: any) => void }>(null);
|
||||
const [customModal, setCustomModal] = useState<null | { title?: string; node: React.ReactNode }>(null);
|
||||
|
||||
const value = useMemo<UIContextType>(() => ({
|
||||
loading,
|
||||
showLoading: (text?: string) => {
|
||||
setLoadingText(text || 'Loading...');
|
||||
setLoadingText(text || t('loading'));
|
||||
setLoading(true);
|
||||
},
|
||||
hideLoading: () => setLoading(false),
|
||||
@@ -37,7 +39,7 @@ export const UIProvider: React.FC<{ children: React.ReactNode }> = ({ children }
|
||||
}),
|
||||
openModal: (node, title) => setCustomModal({ node, title }),
|
||||
closeModal: () => setCustomModal(null),
|
||||
}), [loading]);
|
||||
}), [loading, t]);
|
||||
|
||||
const closeDialog = (result: boolean) => {
|
||||
if (!dialog) return;
|
||||
@@ -76,7 +78,7 @@ export const UIProvider: React.FC<{ children: React.ReactNode }> = ({ children }
|
||||
<motion.div className="w-full max-w-4xl rounded-2xl border border-zinc-700 bg-zinc-900 shadow-2xl overflow-hidden"
|
||||
initial={{ scale: 0.96 }} animate={{ scale: 1 }} exit={{ scale: 0.96 }}>
|
||||
<div className="px-5 py-3 border-b border-zinc-800 flex items-center justify-between">
|
||||
<h3 className="text-sm font-semibold text-zinc-100">{customModal.title || 'Modal'}</h3>
|
||||
<h3 className="text-sm font-semibold text-zinc-100">{customModal.title || t('modal')}</h3>
|
||||
<button onClick={() => setCustomModal(null)} className="text-zinc-400 hover:text-zinc-200">✕</button>
|
||||
</div>
|
||||
<div className="p-4 max-h-[80vh] overflow-auto">{customModal.node}</div>
|
||||
|
||||
Reference in New Issue
Block a user