Add foundational components and logic for migration, UI design, and input handling
- Introduced foundational UI components (`Badge`, `LockCard`, `SectionHeader`, `AvatarIcon`, etc.) for flexible layouts and consistent design. - Added migration support with the `MigrationModal` component and backend integration for exporting/importing data between Electron and Tauri. - Extended form components with `TextAreaInput`, `OrderInput`, `ToggleField`, and `ToolbarSelect` for improved input handling. - Updated `ScribeShell` with migration popup logic to prompt users for data migration. - Integrated `AlertStack` for better alert handling and notification management. - Enhanced Rust/Tauri services with migration command implementations. - Added translations and styles for new components.
This commit is contained in:
@@ -450,6 +450,79 @@ ipcMain.on('logout', ():void => {
|
||||
createLoginWindow();
|
||||
});
|
||||
|
||||
// ========== MIGRATION EXPORT (Electron → Tauri) ==========
|
||||
|
||||
ipcMain.handle('export-migration', async ():Promise<{success: boolean; path?: string; error?: string}> => {
|
||||
const storage:SecureStorage = getSecureStorage();
|
||||
const userId:string | null = storage.get<string>('userId', null);
|
||||
const lastUserId:string | null = storage.get<string>('lastUserId', null);
|
||||
|
||||
const targetUserId:string | null = userId || lastUserId;
|
||||
if (!targetUserId) {
|
||||
return { success: false, error: 'No user found in storage' };
|
||||
}
|
||||
|
||||
let encryptionKey:string | null = null;
|
||||
try {
|
||||
encryptionKey = getUserEncryptionKey(targetUserId);
|
||||
} catch {
|
||||
return { success: false, error: 'Encryption key not found for this user' };
|
||||
}
|
||||
|
||||
const pinHash:string | null = storage.get<string>(`pin-${targetUserId}`, null);
|
||||
|
||||
const userDataPath:string = app.getPath('userData');
|
||||
const dbPath:string = path.join(userDataPath, 'eritors-local.db');
|
||||
|
||||
if (!fs.existsSync(dbPath)) {
|
||||
return { success: false, error: 'No local database found' };
|
||||
}
|
||||
|
||||
const { filePath } = await dialog.showSaveDialog({
|
||||
title: 'Export migration data',
|
||||
defaultPath: path.join(app.getPath('desktop'), 'eritors-migration.json'),
|
||||
filters: [{ name: 'Migration', extensions: ['json'] }],
|
||||
});
|
||||
|
||||
if (!filePath) {
|
||||
return { success: false, error: 'Export cancelled' };
|
||||
}
|
||||
|
||||
const migrationData = {
|
||||
version: 1,
|
||||
exported_at: Date.now(),
|
||||
user_id: targetUserId,
|
||||
encryption_key: encryptionKey,
|
||||
pin_hash: pinHash,
|
||||
db_source: dbPath,
|
||||
};
|
||||
|
||||
try {
|
||||
fs.writeFileSync(filePath, JSON.stringify(migrationData, null, 2), 'utf-8');
|
||||
|
||||
// Copier aussi la DB à côté du fichier de migration
|
||||
const dbDestination:string = path.join(path.dirname(filePath), `eritors-local-${targetUserId}.db`);
|
||||
fs.copyFileSync(dbPath, dbDestination);
|
||||
|
||||
// Copier WAL et SHM si existants
|
||||
const walPath:string = dbPath + '-wal';
|
||||
const shmPath:string = dbPath + '-shm';
|
||||
if (fs.existsSync(walPath)) {
|
||||
fs.copyFileSync(walPath, dbDestination + '-wal');
|
||||
}
|
||||
if (fs.existsSync(shmPath)) {
|
||||
fs.copyFileSync(shmPath, dbDestination + '-shm');
|
||||
}
|
||||
|
||||
return { success: true, path: filePath };
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Export failed',
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// ========== USER SYNC (PRE-AUTHENTICATION) ==========
|
||||
|
||||
interface SyncUserData {
|
||||
|
||||
Reference in New Issue
Block a user