'use client'; import React, { useState, useEffect } from 'react'; import { configManager, AppSettings, CostSettings } from '@/lib/config/storage'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Switch } from '@/components/ui/switch'; import { toast } from 'sonner'; import { useTheme } from 'next-themes'; import { DollarSign, AlertTriangle, Info, Download, Upload, Database, ChevronDown, Palette, Shield } from 'lucide-react'; import { CostCalculator } from '@/lib/llm/cost-calculator'; import { AboutModal } from '@/components/about-modal'; import { BackupService } from '@/lib/vfs/backup-service'; import { setTelemetryOptIn, track } from '@/lib/telemetry'; import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible'; import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group'; import { PermissionMatrix } from '@/components/permissions/PermissionMatrix'; export function SettingsPanel() { const [, setSettings] = useState({}); const [costSettings, setCostSettings] = useState({}); const { theme, setTheme } = useTheme(); const [mounted, setMounted] = useState(false); const [aboutModalOpen, setAboutModalOpen] = useState(false); const [isExporting, setIsExporting] = useState(false); const [isImporting, setIsImporting] = useState(false); const [importProgress, setImportProgress] = useState(0); const [importMessage, setImportMessage] = useState(''); const [telemetryOptIn, setTelemetryOptInState] = useState(() => configManager.getSettings().telemetryOptIn !== false ); const [openSections, setOpenSections] = useState({ application: true, permissions: false, costTracking: true, dataManagement: true }); useEffect(() => { // Load settings on mount setSettings(configManager.getSettings()); setCostSettings(configManager.getCostSettings()); setMounted(true); }, []); const updateSetting = ( key: K, value: AppSettings[K] ) => { configManager.setSetting(key, value); setSettings(prev => ({ ...prev, [key]: value })); }; const clearSettings = () => { if (confirm('Are you sure you want to clear all settings?')) { configManager.clearSettings(); setSettings({}); toast.success('Settings cleared'); } }; const handleExportData = async () => { try { setIsExporting(true); await BackupService.exportAllData(); toast.success('Data exported successfully!'); track('project_export', { format: 'osws' }); } catch (error) { toast.error(error instanceof Error ? error.message : 'Export failed'); } finally { setIsExporting(false); } }; const handleImportData = () => { const input = document.createElement('input'); input.type = 'file'; input.accept = '.osws'; input.onchange = async (e) => { const file = (e.target as HTMLInputElement).files?.[0]; if (!file) return; try { setIsImporting(true); setImportProgress(0); setImportMessage('Validating file...'); const validation = await BackupService.validateBackupFile(file); if (!validation.valid) { toast.error(`Invalid backup file: ${validation.reason}`); return; } const shouldReplace = confirm( `Import ${validation.metadata?.projectCount || 0} projects?\n\n` + 'Choose OK to REPLACE all current data, or Cancel to MERGE with existing data.' ); await BackupService.importAllData(file, { mode: shouldReplace ? 'replace' : 'merge', onProgress: (progress, message) => { setImportProgress(progress); setImportMessage(message); } }); toast.success('Data imported successfully!'); track('project_import', { format: 'osws' }); setTimeout(() => window.location.reload(), 1000); } catch (error) { toast.error(error instanceof Error ? error.message : 'Import failed'); } finally { setIsImporting(false); setImportProgress(0); setImportMessage(''); } }; input.click(); }; const toggleSection = (section: keyof typeof openSections) => { setOpenSections(prev => ({ ...prev, [section]: !prev[section] })); }; return (
{/* Header */}

Settings

Application preferences and data management

{/* Scrollable content */}
{/* Application Settings Section */} toggleSection('application')} >

Application Settings

Configure your preferences and display options

{/* Theme */}
{ if (value) { setTheme(value); updateSetting('theme', value as 'light' | 'dark' | 'system'); } }} className="w-full mt-2" > Dark Light System
{/* Telemetry */}

Help improve OSW Studio by sharing anonymous usage data

{ setTelemetryOptInState(checked); setTelemetryOptIn(checked); }} />
{/* Permissions Section */} toggleSection('permissions')} >

Permissions

{/* Cost Tracking Section */} toggleSection('costTracking')} >

Cost Tracking

{/* Show Costs */}

Show cost information in messages

{ const newCostSettings = { ...costSettings, showCosts: checked }; configManager.setCostSettings(newCostSettings); setCostSettings(newCostSettings); }} />
{/* Daily + Project Limits — 2 column grid */}
{ const value = e.target.value ? parseFloat(e.target.value) : undefined; const newCostSettings = { ...costSettings, dailyLimit: value }; configManager.setCostSettings(newCostSettings); setCostSettings(newCostSettings); }} />
{ const value = e.target.value ? parseFloat(e.target.value) : undefined; const newCostSettings = { ...costSettings, projectLimit: value }; configManager.setCostSettings(newCostSettings); setCostSettings(newCostSettings); }} />
{/* Warning Threshold */}
{ const value = parseInt(e.target.value); const newCostSettings = { ...costSettings, warningThreshold: value }; configManager.setCostSettings(newCostSettings); setCostSettings(newCostSettings); }} /> Warn at {costSettings.warningThreshold || 80}%
{/* Lifetime Costs */}
Lifetime Total
{CostCalculator.formatCost(configManager.getLifetimeCosts().total)}
{/* Data Management Section */} toggleSection('dataManagement')} >

Data Management

Backup and restore your projects, conversations, and settings.

{/* Export Data */}
Export All Data
Download a backup of all projects and data
{/* Import Data */}
Import Data
Restore from a .osws backup file
{/* Import Progress */} {isImporting && (
{importMessage} {importProgress}%
)}
{/* end scrollable content */} {/* Footer */}
); }