import React, { useEffect, useMemo, useState } from 'react'; import { Bot, CheckCircle2, KeyRound, LogOut, Server, Settings, Shield, UserCircle, Users } from 'lucide-react'; import { motion } from 'framer-motion'; import { useAuth } from '../context/useAuth'; import { getDefaultModel, getDefaultProvider, providerOptions, saveProviderDefaults } from '../services/llmConfig'; import type { SupportedProvider } from '../services/llmConfig'; import { getApiUrl, getAppVersion, getSupabaseUrl } from '../services/runtimeConfig'; import type { UiMode } from '../services/uiMode'; import { supabase } from '../services/supabase'; interface ProfileRow { id: string; role: 'user' | 'manager' | 'admin'; full_name: string | null; avatar_url: string | null; } const SettingsView: React.FC<{ uiMode: UiMode; onUiModeChange: (mode: UiMode) => void }> = ({ uiMode, onUiModeChange }) => { const { user, session, profile, signOut, refreshProfile } = useAuth(); const initialProvider = useMemo(() => getDefaultProvider(), []); const [provider, setProvider] = useState(initialProvider); const [model, setModel] = useState(getDefaultModel(initialProvider)); const [saved, setSaved] = useState(false); const [fullName, setFullName] = useState(''); const [avatarUrl, setAvatarUrl] = useState(''); const [profileMessage, setProfileMessage] = useState(null); const [savingProfile, setSavingProfile] = useState(false); const [profiles, setProfiles] = useState([]); const [profilesLoading, setProfilesLoading] = useState(false); const [adminMessage, setAdminMessage] = useState(null); const config = useMemo(() => { const apiUrl = getApiUrl() || 'Same origin'; const supabaseUrl = getSupabaseUrl() || 'Not configured'; const appVersion = getAppVersion(); return { apiUrl, supabaseUrl, appVersion }; }, []); const providerModels = providerOptions.find((option) => option.id === provider)?.models ?? []; const isAdmin = profile?.role === 'admin'; useEffect(() => { setFullName(profile?.full_name ?? ''); setAvatarUrl(profile?.avatar_url ?? ''); }, [profile]); useEffect(() => { if (!isAdmin) return; const loadProfiles = async () => { setProfilesLoading(true); const { data } = await supabase .from('profiles') .select('id,role,full_name,avatar_url') .order('created_at', { ascending: false }); setProfiles(data ?? []); setProfilesLoading(false); }; loadProfiles(); }, [isAdmin, adminMessage]); const updateProvider = (value: SupportedProvider) => { setProvider(value); setModel(getDefaultModel(value)); setSaved(false); }; const saveDefaults = () => { saveProviderDefaults(provider, model); setSaved(true); }; const saveProfile = async () => { if (!user) return; setSavingProfile(true); setProfileMessage(null); const { error } = await supabase .from('profiles') .upsert( { id: user.id, role: profile?.role ?? 'user', full_name: fullName.trim() || null, avatar_url: avatarUrl.trim() || null, updated_at: new Date().toISOString(), }, { onConflict: 'id' } ); if (error) { setProfileMessage(error.message); setSavingProfile(false); return; } await refreshProfile(); setProfileMessage('Profile updated.'); setSavingProfile(false); }; const updateUserRole = async (profileId: string, role: 'user' | 'admin') => { setAdminMessage(null); const { error } = await supabase .from('profiles') .update({ role, updated_at: new Date().toISOString() }) .eq('id', profileId); if (error) { setAdminMessage(error.message); return; } setProfiles((current) => current.map((entry) => (entry.id === profileId ? { ...entry, role } : entry))); if (profileId === user?.id) { await refreshProfile(); } setAdminMessage('User roles updated.'); }; return (

Settings

Review environment, session, and security configuration.

Session

Profile

{profileMessage &&

{profileMessage}

}

Runtime

Workspace Mode

Guided keeps the product focused on the main workflow. Expert exposes the full tool surface.

LLM Defaults

These defaults are used when creating new agents from the UI. API keys stay in backend `.env`.

{saved &&

LLM defaults saved.

}

Security

{isAdmin && (

User Management

Manage profile roles for users in this workspace.

{adminMessage &&
{adminMessage}
}
{profilesLoading &&

Loading users...

} {!profilesLoading && profiles.length === 0 &&

No profiles found.

} {profiles.map((entry) => (
{entry.full_name || 'Unnamed user'}

{entry.id}

))}
)}

Account

Signing out clears the local Supabase session and returns to the login screen.

); }; const SettingRow: React.FC<{ label: string; value: string }> = ({ label, value }) => (
{label} {value}
); export default SettingsView;