import { useEffect, useState } from "react" import { ArrowClockwise, CheckCircle, ClockCounterClockwise, Download, Trash } from "@phosphor-icons/react" import type { ProfileSnapshot, SecretRecord } from "@shared/types" import type { AppLocale } from "@shared/locale" import { APP_LOCALES, LOCALE_LABELS } from "@shared/locale" import { useLocale, useT } from "../../i18n" import { formatTime } from "../../lib/formatters" import { unwrap } from "../../lib/desktop" import { ActionButton, ConfirmDialog, EmptyState, InlineNotice, Select } from "../ui" import { describeActionError } from "./execution-utils" import { useAppStore } from "../../state/store" export function SettingsPane({ snapshot, secrets, companyId, onSaved }: { snapshot: ProfileSnapshot; secrets: SecretRecord[]; companyId: string; onSaved: () => Promise }) { const t = useT(); const currentLocale = useLocale(); const addToast = useAppStore((s) => s.addToast) const [theme, setTheme] = useState(snapshot.theme); const [selectedLocale, setSelectedLocale] = useState(snapshot.locale ?? currentLocale); const [updatesEnabled, setUpdatesEnabled] = useState(snapshot.updatesEnabled) const [confirmDeleteSecretId, setConfirmDeleteSecretId] = useState(null); const [actionError, setActionError] = useState(null); const [actionNotice, setActionNotice] = useState(null) const [deleteSecretError, setDeleteSecretError] = useState(null); const [loadingAction, setLoadingAction] = useState<"save"|"check"|"backup"|"restore"|null>(null) const secretToDelete = secrets.find((s) => s.id === confirmDeleteSecretId) ?? null useEffect(() => { setTheme(snapshot.theme); setUpdatesEnabled(snapshot.updatesEnabled); if (snapshot.locale) setSelectedLocale(snapshot.locale) }, [snapshot.theme, snapshot.updatesEnabled, snapshot.locale]) async function handleDeleteSecret(id: string) { setDeleteSecretError(null); setActionError(null); setActionNotice(null); try { unwrap(await window.agentCompany.deleteSecret({ id, companyId })); setConfirmDeleteSecretId(null); setActionNotice("Secret deleted."); addToast("Secret deleted", "success"); await onSaved() } catch (e) { setDeleteSecretError(describeActionError(e)) } } async function handleSaveSettings() { setActionError(null); setActionNotice(null); setLoadingAction("save"); try { unwrap(await window.agentCompany.updateSettings({ theme, locale: selectedLocale, updatesEnabled })); await onSaved(); setActionNotice("Settings saved."); addToast("Settings saved", "success") } catch (e) { setActionError(describeActionError(e)) } finally { setLoadingAction(null) } } async function handleCheckForUpdates() { setActionError(null); setActionNotice(null); setLoadingAction("check"); try { const started = unwrap(await window.agentCompany.checkForUpdates()); setActionNotice(started ? "Update check started." : "Update check skipped because no release update feed is configured.") } catch (e) { setActionError(describeActionError(e)) } finally { setLoadingAction(null) } } async function handleBackupProfile() { setActionError(null); setActionNotice(null); setLoadingAction("backup"); try { const backupPath = unwrap(await window.agentCompany.backupProfile()); if (backupPath) { setActionNotice(`Profile backup created at ${backupPath}.`); addToast("Profile backup created", "success") } } catch (e) { setActionError(describeActionError(e)) } finally { setLoadingAction(null) } } async function handleRestoreProfile() { setActionError(null); setActionNotice(null); setLoadingAction("restore"); try { const restored = unwrap(await window.agentCompany.restoreProfile()); if (!restored) return; await onSaved(); setActionNotice("Profile restored."); addToast("Profile restored", "success") } catch (e) { setActionError(describeActionError(e)) } finally { setLoadingAction(null) } } return (
confirmDeleteSecretId && void handleDeleteSecret(confirmDeleteSecretId)} onCancel={() => { setDeleteSecretError(null); setConfirmDeleteSecretId(null) }} /> {actionError ? : null} {!actionError && actionNotice ? : null}
{t("exec.profile")}
{t("exec.profilePath")}
{snapshot.profilePath}
{t("exec.preferences")}
setSelectedLocale(v as AppLocale)} options={APP_LOCALES.map((loc) => ({ value: loc, label: LOCALE_LABELS[loc] }))} />
{(() => { const company = snapshot.companies.find((c) => c.id === companyId); if (!company) return null; const isCeo = company.executionMode !== "ai_cofounder"; return (
{t("exec.executionMode")}
) })()}
Keyboard Shortcuts
{([ [navigator.platform.includes("Mac") ? "⌘K" : "Ctrl+K", "Open command palette"], [navigator.platform.includes("Mac") ? "⌘Enter" : "Ctrl+Enter", "Send message"], ["Escape", "Close modal / palette"], ["↑ / ↓", "Navigate palette results"], ["Enter", "Select palette result"], ["Tab", "Move focus between elements"], ] as const).map(([key, desc]) => (
{desc} {key}
))}
{t("exec.actions")}
void handleSaveSettings()} icon={CheckCircle} loading={loadingAction === "save"} /> void handleCheckForUpdates()} icon={Download} loading={loadingAction === "check"} /> void handleBackupProfile()} icon={ClockCounterClockwise} loading={loadingAction === "backup"} /> void handleRestoreProfile()} icon={ArrowClockwise} loading={loadingAction === "restore"} />
{t("exec.secretBackend")}
{snapshot.backend.secretBackend}
{t("exec.secrets")} ({secrets.length})
{secrets.length === 0 ? :
{secrets.map((s) => )}
{t("exec.secretName")}{t("exec.secretDescription")}{t("exec.secretBackendCol")}{t("exec.secretUpdated")}
{s.name}{s.description || "\u2014"}{s.backend}{formatTime(s.updatedAt)} setConfirmDeleteSecretId(s.id)} icon={Trash} tone="danger" />
}
) }