/* Instellingen screen */ function SchermInstellingen() { const [providers, setProviders] = useState({}); const [form, setForm] = useState({ provider: 'anthropic', api_key: '', base_url: 'http://localhost:11434', region: 'eu-central-1' }); const [status, setStatus] = useState(null); const [testen, setTesten] = useState(false); const [logboek, setLogboek] = useState([]); const [logLaden, setLogLaden] = useState(false); const isOllama = form.provider === 'ollama'; const isBedrock = form.provider === 'bedrock'; // Standaard provider + model voor de pipeline-startform const [std, setStd] = useState({ provider: 'anthropic', model: '' }); const [stdOllamaModellen, setStdOllamaModellen] = useState([]); const [stdStatus, setStdStatus] = useState(null); const [stdBezig, setStdBezig] = useState(false); const [providerModellen, setProviderModellen] = useState({}); const [modelForm, setModelForm] = useState({ provider: 'anthropic', nieuw: '' }); const [modelStatus, setModelStatus] = useState(null); async function laadModellen() { try { const d = await fetch(`${API}/config/providers/models`).then(r => r.ok ? r.json() : {}); setProviderModellen(d); } catch (e) {} } useEffect(() => { laadModellen(); }, []); async function laadStandaard() { const d = await fetch(`${API}/config/standaard`).then(r => r.ok ? r.json() : {}).catch(() => ({})); if (d && d.provider) setStd({ provider: d.provider, model: d.model || '' }); } useEffect(() => { laadStandaard(); }, []); useEffect(() => { if (std.provider !== 'ollama') { setStdOllamaModellen([]); return; } fetch(`${API}/config/providers/ollama/models`) .then(r => r.ok ? r.json() : { models: [] }) .then(d => setStdOllamaModellen(d.models || [])) .catch(() => setStdOllamaModellen([])); }, [std.provider]); const stdModelOpties = std.provider === 'ollama' ? stdOllamaModellen : (providerModellen[std.provider] || []); async function slaStandaardOp() { setStdStatus(null); setStdBezig(true); try { const r = await fetch(`${API}/config/standaard`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ provider: std.provider, model: std.model || null }), }); setStdStatus(r.ok ? { kind: 'success', msg: 'Standaard opgeslagen.' } : { kind: 'error', msg: 'Opslaan mislukt.' }); } catch (e) { setStdStatus({ kind: 'error', msg: `Opslaan mislukt: ${e.message}` }); } finally { setStdBezig(false); } } async function laadLogboek() { setLogLaden(true); try { const d = await fetch(`${API}/auth-log?limit=100`).then(r => r.ok ? r.json() : []).catch(() => []); setLogboek(Array.isArray(d) ? d : []); } finally { setLogLaden(false); } } useEffect(() => { laadLogboek(); }, []); const LOG_KIND = { login_ok: 'success', login_fout: 'error', lockout: 'warning', logout: 'neutral' }; const LOG_LABEL = { login_ok: 'Ingelogd', login_fout: 'Mislukt', lockout: 'Geblokkeerd', logout: 'Uitgelogd' }; async function laad() { const p = await fetch(`${API}/config/providers`).then(r => r.json()).catch(() => ({})); setProviders(p); const details = await fetch(`${API}/config/providers/public`).then(r => r.json()).catch(() => ({})); setForm(f => ({ ...f, base_url: details.ollama?.base_url || f.base_url, region: details.bedrock?.region || f.region, })); } useEffect(() => { laad(); }, []); async function opslaan() { setStatus(null); const r = await fetch(`${API}/config/providers`, { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify(form) }); if (r.ok) { setStatus({ kind: 'success', msg: 'Opgeslagen.' }); setForm(f => ({...f, api_key: ''})); laad(); } else { setStatus({ kind: 'error', msg: 'Opslaan mislukt.' }); } } async function testProvider() { setStatus(null); setTesten(true); try { const params = new URLSearchParams(); if (isOllama && form.base_url) params.append('base_url', form.base_url); if (!isOllama && form.api_key) params.append('api_key', form.api_key); const qs = params.toString() ? `?${params.toString()}` : ''; const data = await fetch(`${API}/config/providers/test/${form.provider}${qs}`).then(r => r.json()); if (data.ok) { const extra = isOllama && data.models?.length ? ` Modellen: ${data.models.join(', ')}` : ''; setStatus({ kind: 'success', msg: `Verbinding werkt.${extra}` }); } else { setStatus({ kind: 'error', msg: `Test mislukt: ${data.fout || 'onbekende fout'}` }); } } catch(e) { setStatus({ kind: 'error', msg: `Test mislukt: ${e.message}` }); } finally { setTesten(false); } } async function voegModelToe() { const naam = modelForm.nieuw.trim(); if (!naam) return; const huidig = providerModellen[modelForm.provider] || []; if (huidig.includes(naam)) { setModelStatus({ kind: 'error', msg: `"${naam}" staat al in de lijst.` }); return; } const nieuw = [...huidig, naam]; setModelStatus(null); try { const r = await fetch(`${API}/config/providers/models`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ provider: modelForm.provider, models: nieuw }), }); if (r.ok) { setProviderModellen(p => ({ ...p, [modelForm.provider]: nieuw })); setModelForm(f => ({ ...f, nieuw: '' })); setModelStatus({ kind: 'success', msg: `"${naam}" toegevoegd.` }); laadModellen(); } else { setModelStatus({ kind: 'error', msg: 'Toevoegen mislukt.' }); } } catch (e) { setModelStatus({ kind: 'error', msg: `Toevoegen mislukt: ${e.message}` }); } } async function verwijderModel(model) { const huidig = providerModellen[modelForm.provider] || []; const nieuw = huidig.filter(m => m !== model); setModelStatus(null); try { const r = await fetch(`${API}/config/providers/models`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ provider: modelForm.provider, models: nieuw }), }); if (r.ok) { setProviderModellen(p => ({ ...p, [modelForm.provider]: nieuw })); setModelStatus({ kind: 'success', msg: `"${model}" verwijderd.` }); laadModellen(); } else { setModelStatus({ kind: 'error', msg: 'Verwijderen mislukt.' }); } } catch (e) { setModelStatus({ kind: 'error', msg: `Verwijderen mislukt: ${e.message}` }); } } return (

Instellingen

Configureer AI-providers en systeemopties.

AI Providers

{status && {status.msg}}
{isOllama && ( setForm(f => ({...f, base_url: e.target.value}))} /> )} {isBedrock && ( setForm(f => ({...f, region: e.target.value}))} /> )} {!isOllama && !isBedrock && ( setForm(f => ({...f, api_key: e.target.value}))} /> )}
Opslaan {testen ? 'Testen...' : 'Test verbinding'}
Geconfigureerde providers
{Object.entries(providers).map(([k,v]) => (
{k} {v ? Geconfigureerd : Niet ingesteld}
))}

Standaard voor pipeline

Provider en model die de pipeline-startform standaard voorinvult.

{stdStatus && {stdStatus.msg}}
setStd(s => ({ ...s, model: e.target.value }))} /> {stdModelOpties.map(m =>
{stdBezig ? 'Opslaan…' : 'Opslaan als standaard'}

Modellen per provider

Voeg modellen toe of verwijder ze per provider. Ollama-modellen worden automatisch opgehaald.

{modelStatus && {modelStatus.msg}}
setModelForm(f => ({ ...f, nieuw: e.target.value }))} onKeyDown={e => { if (e.key === 'Enter' && modelForm.nieuw.trim()) voegModelToe(); }} /> Toevoegen
{providerModellen[modelForm.provider] && providerModellen[modelForm.provider].length > 0 && (
Modellen voor {modelForm.provider}
{providerModellen[modelForm.provider].map((m, i) => ( {m} ))}
)} {(!providerModellen[modelForm.provider] || providerModellen[modelForm.provider].length === 0) && (
Geen modellen geconfigureerd voor {modelForm.provider}.
)}

Inlogpogingen

{logLaden ? 'Laden…' : 'Vernieuwen'}
{logboek.length === 0 ? (
Nog geen inloggebeurtenissen vastgelegd.
) : (
{logboek.map((r, i) => ( ))}
TijdGebeurtenisGebruikerIPDetail
{(r.tijd || '').replace('T',' ').slice(0,19)} {LOG_LABEL[r.gebeurtenis] || r.gebeurtenis} {r.gebruikersnaam || '—'} {r.ip || '—'} {r.detail || (r.user_agent ? r.user_agent.slice(0,60) : '')}
)}
); } window.SchermInstellingen = SchermInstellingen;