()
| 2173 | } |
| 2174 | |
| 2175 | function DataTab() { |
| 2176 | const store = useStore() |
| 2177 | const { conversations, clearConversations } = store |
| 2178 | const [showConfirm, setShowConfirm] = useState(false) |
| 2179 | const [importStatus, setImportStatus] = useState<'idle' | 'success' | 'error'>('idle') |
| 2180 | const [importMessage, setImportMessage] = useState('') |
| 2181 | const [pendingImport, setPendingImport] = useState<Record<string, unknown> | null>(null) |
| 2182 | const [pendingImportSummary, setPendingImportSummary] = useState('') |
| 2183 | |
| 2184 | const MAX_IMPORT_SIZE = 10 * 1024 * 1024 // 10 MB |
| 2185 | |
| 2186 | // Estimate localStorage usage |
| 2187 | const storageUsed = (() => { |
| 2188 | try { |
| 2189 | let total = 0 |
| 2190 | for (let i = 0; i < localStorage.length; i++) { |
| 2191 | const key = localStorage.key(i) |
| 2192 | if (key) total += key.length + (localStorage.getItem(key)?.length || 0) |
| 2193 | } |
| 2194 | return total * 2 // UTF-16 = 2 bytes per char |
| 2195 | } catch { return 0 } |
| 2196 | })() |
| 2197 | const STORAGE_CAP = 5 * 1024 * 1024 // ~5 MB typical browser limit |
| 2198 | const storagePercent = Math.min(100, Math.round((storageUsed / STORAGE_CAP) * 100)) |
| 2199 | const formatBytes = (b: number) => b < 1024 ? `${b} B` : b < 1048576 ? `${(b / 1024).toFixed(1)} KB` : `${(b / 1048576).toFixed(1)} MB` |
| 2200 | |
| 2201 | const handleExport = () => { |
| 2202 | // Export everything persisted to localStorage — full self-custody backup. |
| 2203 | // STM modules excluded: transformer functions can't be serialized to JSON. |
| 2204 | // STM enabled/disabled state is restored from defaults on import. |
| 2205 | const exportData = { |
| 2206 | _version: 1, |
| 2207 | _exportedAt: new Date().toISOString(), |
| 2208 | _source: 'g0dm0d3', |
| 2209 | // Conversations (chat history) |
| 2210 | conversations: store.conversations, |
| 2211 | currentConversationId: store.currentConversationId, |
| 2212 | // Settings |
| 2213 | theme: store.theme, |
| 2214 | defaultModel: store.defaultModel, |
| 2215 | currentPersona: store.currentPersona, |
| 2216 | apiKey: store.apiKey, |
| 2217 | // Features |
| 2218 | autoTuneEnabled: store.autoTuneEnabled, |
| 2219 | autoTuneStrategy: store.autoTuneStrategy, |
| 2220 | autoTuneOverrides: store.autoTuneOverrides, |
| 2221 | feedbackState: store.feedbackState, |
| 2222 | parseltongueConfig: store.parseltongueConfig, |
| 2223 | // Memory system |
| 2224 | memories: store.memories, |
| 2225 | memoriesEnabled: store.memoriesEnabled, |
| 2226 | // System prompt |
| 2227 | customSystemPrompt: store.customSystemPrompt, |
| 2228 | useCustomSystemPrompt: store.useCustomSystemPrompt, |
| 2229 | // Mode config |
| 2230 | consortiumEnabled: store.consortiumEnabled, |
| 2231 | consortiumTier: store.consortiumTier, |
| 2232 | liquidResponseEnabled: store.liquidResponseEnabled, |
nothing calls this directly
no test coverage detected