import { useEffect, useState } from 'react'; import type { AppConfig } from '../api/client'; import { api } from '../api/client'; export default function SettingsPage() { const [config, setConfig] = useState(null); const [loading, setLoading] = useState(true); const [saving, setSaving] = useState(false); const [message, setMessage] = useState(''); useEffect(() => { api.getConfig().then(c => { setConfig(c); setLoading(false); }).catch(() => setLoading(false)); }, []); async function handleSave(e: React.FormEvent) { e.preventDefault(); if (!config) return; setSaving(true); setMessage(''); try { await api.updateConfig({ OPENCLAW_WORKSPACE: config.OPENCLAW_WORKSPACE, GITEA_SERVER: config.GITEA_SERVER, DEPLOYMENT_SERVER: config.DEPLOYMENT_SERVER, DEPLOYMENT_USER: config.DEPLOYMENT_USER, LOG_LEVEL: config.LOG_LEVEL, }); setMessage('✅ Configuration sauvegardée'); } catch (err) { setMessage('❌ ' + (err instanceof Error ? err.message : 'Erreur')); } setSaving(false); } if (loading || !config) { return
🦊
; } const fields: { key: keyof AppConfig; label: string; icon: string; editable: boolean; secret?: boolean }[] = [ { key: 'OPENCLAW_WORKSPACE', label: 'Workspace OpenClaw', icon: '📁', editable: true }, { key: 'GITEA_SERVER', label: 'Serveur Gitea', icon: '🌐', editable: true }, { key: 'GITEA_OPENCLAW_TOKEN', label: 'Token Gitea', icon: '🔑', editable: false, secret: true }, { key: 'DEPLOYMENT_SERVER', label: 'Serveur de déploiement', icon: '🖥️', editable: true }, { key: 'DEPLOYMENT_USER', label: 'Utilisateur déploiement', icon: '👤', editable: true }, { key: 'DEPLOYMENT_PWD', label: 'Mot de passe déploiement', icon: '🔒', editable: false, secret: true }, { key: 'TELEGRAM_BOT_TOKEN', label: 'Token Telegram', icon: '🤖', editable: false, secret: true }, { key: 'TELEGRAM_CHAT_ID', label: 'Chat ID Telegram', icon: '💬', editable: true }, { key: 'LOG_LEVEL', label: 'Niveau de log', icon: '📊', editable: true }, ]; return (

⚙️ Configuration

{message && (
{message}
)} {fields.map(f => (
setConfig({ ...config, [f.key]: e.target.value })} disabled={!f.editable} type={f.secret ? 'password' : 'text'} />
))}
{/* Workflows info */}
); } function WorkflowsInfo() { const [workflows, setWorkflows] = useState<{ type: string; label: string; steps: { agent: string; model: string }[] }[]>([]); useEffect(() => { api.listWorkflows().then(setWorkflows).catch(() => {}); }, []); if (workflows.length === 0) return null; return (

🔄 Workflows disponibles

{workflows.map(wf => (

{wf.label}

{wf.steps.map((s, i) => (
{s.agent} {i < wf.steps.length - 1 && }
))}
))}
); }