Release 1.2.0: Remove backup encryption and switch to JSON-only backups with history support

This commit is contained in:
michael.borak
2026-01-24 13:10:18 +01:00
parent 897f2ec0c2
commit a3e4fa4ec7
2 changed files with 229 additions and 121 deletions

View File

@@ -1,4 +1,5 @@
import { useState } from 'react';
import { useState, useEffect, useCallback } from 'react';
import { invoke } from '@tauri-apps/api/core';
import { Settings as SettingsIcon } from "lucide-react";
import Settings, { SmtpConfig, AzureConfig } from "./components/Settings";
import Recorder from "./components/Recorder";
@@ -60,6 +61,11 @@ function App() {
return localStorage.getItem('hearbit_selected_model') || 'mixtral';
});
// Daily Backup State
const [dailyBackupEnabled, setDailyBackupEnabled] = useState(() => localStorage.getItem('hearbit_daily_backup_enabled') === 'true');
const [dailyBackupPath, setDailyBackupPath] = useState(() => localStorage.getItem('hearbit_daily_backup_path') || '');
const [lastBackupDate, setLastBackupDate] = useState(() => localStorage.getItem('hearbit_last_backup_date') || '');
const handleModelChange = (model: string) => {
setSelectedModel(model);
localStorage.setItem('hearbit_selected_model', model);
@@ -227,6 +233,7 @@ Thanks!`
return saved ? JSON.parse(saved) : defaultEmailTemplates;
});
const handleSaveSettings = (
newApiKey: string,
newProductId: string,
@@ -234,7 +241,9 @@ Thanks!`
newSavePath: string,
newSmtp: SmtpConfig,
newAzure: AzureConfig,
newEmailTemplates: EmailTemplate[]
newEmailTemplates: EmailTemplate[],
newDailyBackupEnabled: boolean,
newDailyBackupPath: string
) => {
setApiKey(newApiKey);
setProductId(newProductId);
@@ -244,14 +253,20 @@ Thanks!`
setAzureConfig(newAzure);
setEmailTemplates(newEmailTemplates);
localStorage.setItem('infomaniak_api_key', newApiKey);
localStorage.setItem('infomaniak_product_id', newProductId);
localStorage.setItem('infomaniak_prompts', JSON.stringify(newPrompts));
localStorage.setItem('infomaniak_save_path', newSavePath);
setDailyBackupEnabled(newDailyBackupEnabled);
setDailyBackupPath(newDailyBackupPath);
localStorage.setItem('hearbit_api_key', newApiKey);
localStorage.setItem('hearbit_product_id', newProductId);
localStorage.setItem('hearbit_prompts', JSON.stringify(newPrompts));
localStorage.setItem('hearbit_save_path', newSavePath);
localStorage.setItem('hearbit_smtp_config', JSON.stringify(newSmtp));
localStorage.setItem('hearbit_azure_config', JSON.stringify(newAzure));
localStorage.setItem('hearbit_email_templates', JSON.stringify(newEmailTemplates));
localStorage.setItem('hearbit_daily_backup_enabled', String(newDailyBackupEnabled));
localStorage.setItem('hearbit_daily_backup_path', newDailyBackupPath);
setView(lastTab);
};
@@ -332,6 +347,80 @@ Thanks!`
setView('transcription'); // Switch to Transcription view to see content
};
const performBackup = useCallback(async (isAuto = false) => {
try {
if (isAuto && !dailyBackupEnabled) return;
const dataToBackup = {
apiKey,
productId,
prompts,
savePath,
smtp: smtpConfig,
azure: azureConfig,
emailTemplates,
history, // Including history!
// Also include daily backup settings so they persist on restore
dailyBackup: {
enabled: dailyBackupEnabled,
path: dailyBackupPath,
}
};
// Always save as JSON (no encryption)
const content = JSON.stringify(dataToBackup, null, 2);
const dateStr = new Date().toISOString().slice(0, 10);
const fileName = `hearbit_backup_${isAuto ? 'auto_' : ''}${dateStr}.json`;
// Determine path: use specific daily backup path, or general savePath
const targetDir = (isAuto ? dailyBackupPath : savePath) || savePath;
if (!targetDir) {
if (!isAuto) addToast('No backup path configured.', 'error');
return;
}
const fullPath = `${targetDir}/${fileName}`;
await invoke('save_text_file', { path: fullPath, content });
if (isAuto) {
const now = new Date().toISOString();
setLastBackupDate(now);
localStorage.setItem('hearbit_last_backup_date', now);
console.log("Auto-backup completed:", fullPath);
} else {
addToast(`Backup saved to ${fullPath}`, 'success');
}
} catch (e) {
console.error("Backup failed:", e);
if (!isAuto) addToast(`Backup failed: ${e}`, 'error');
}
}, [apiKey, productId, prompts, savePath, smtpConfig, azureConfig, emailTemplates, history, dailyBackupEnabled, dailyBackupPath]);
// Check for Daily Backup on Mount / State Change
useEffect(() => {
if (!dailyBackupEnabled) return;
const check = async () => {
const today = new Date().toISOString().slice(0, 10);
const last = lastBackupDate ? lastBackupDate.slice(0, 10) : '';
if (last !== today) {
// Perform backup
await performBackup(true);
}
};
const timer = setTimeout(() => {
check();
}, 5000); // Check 5s after load to allow state to settle
return () => clearTimeout(timer);
}, [dailyBackupEnabled, lastBackupDate, performBackup]);
return (
@@ -474,6 +563,18 @@ Thanks!`
smtpConfig={smtpConfig}
azureConfig={azureConfig}
emailTemplates={emailTemplates}
// Pass new backup props
dailyBackupEnabled={dailyBackupEnabled}
dailyBackupPath={dailyBackupPath}
lastBackupDate={lastBackupDate}
// Pass history and update callback
history={history}
onHistoryUpdate={(newHistory) => {
setHistory(newHistory);
localStorage.setItem('infomaniak_history', JSON.stringify(newHistory));
}}
/>
)}
</div>