mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-01-10 23:59:45 +08:00
refactor(migration): rename data migration files and update migration logic
This commit renames the data migration files for clarity, changing `dataMigrate.html` to `dataRefactorMigrate.html` and updating the corresponding service imports. It also enhances the migration logic by implementing a new `app_state` table structure and removing deprecated migration files, streamlining the overall migration process.
This commit is contained in:
parent
ff965402cd
commit
92eb5aed7f
@ -103,7 +103,7 @@ export default defineConfig({
|
||||
selectionToolbar: resolve(__dirname, 'src/renderer/selectionToolbar.html'),
|
||||
selectionAction: resolve(__dirname, 'src/renderer/selectionAction.html'),
|
||||
traceWindow: resolve(__dirname, 'src/renderer/traceWindow.html'),
|
||||
dataMigrate: resolve(__dirname, 'src/renderer/dataMigrate.html')
|
||||
dataRefactorMigrate: resolve(__dirname, 'src/renderer/dataRefactorMigrate.html')
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
**THIS IS NOT FOR RUNTIME USE**
|
||||
**THIS DIRECTORY IS NOT FOR RUNTIME USE**
|
||||
|
||||
Using `libsql` as the `sqlite3` driver, and `drizzle` as the ORM and database migration tool
|
||||
|
||||
`migrations/sqlite-drizzle` contains auto-generated migration data. Please **DO NOT** modify it.
|
||||
|
||||
To generate migrations, use the command `yarn run migrations:generate`
|
||||
- Using `libsql` as the `sqlite3` driver, and `drizzle` as the ORM and database migration tool
|
||||
- `migrations/sqlite-drizzle` contains auto-generated migration data. Please **DO NOT** modify it.
|
||||
- If table structure changes, we should run migrations.
|
||||
- To generate migrations, use the command `yarn run migrations:generate`
|
||||
|
||||
@ -1,10 +1,17 @@
|
||||
CREATE TABLE `app_state` (
|
||||
`key` text PRIMARY KEY NOT NULL,
|
||||
`value` text NOT NULL,
|
||||
`description` text,
|
||||
`created_at` integer,
|
||||
`updated_at` integer
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `preference` (
|
||||
`scope` text NOT NULL,
|
||||
`key` text NOT NULL,
|
||||
`value` text,
|
||||
`created_at` integer,
|
||||
`updated_at` integer,
|
||||
`deleted_at` integer
|
||||
`updated_at` integer
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE INDEX `scope_name_idx` ON `preference` (`scope`,`key`);
|
||||
@ -1,9 +1,54 @@
|
||||
{
|
||||
"version": "6",
|
||||
"dialect": "sqlite",
|
||||
"id": "c8c54066-c6f6-404b-a46d-84787ae22485",
|
||||
"id": "de8009d7-95b9-4f99-99fa-4b8795708f21",
|
||||
"prevId": "00000000-0000-0000-0000-000000000000",
|
||||
"tables": {
|
||||
"app_state": {
|
||||
"name": "app_state",
|
||||
"columns": {
|
||||
"key": {
|
||||
"name": "key",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"value": {
|
||||
"name": "value",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"description": {
|
||||
"name": "description",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"preference": {
|
||||
"name": "preference",
|
||||
"columns": {
|
||||
@ -41,13 +86,6 @@
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"deleted_at": {
|
||||
"name": "deleted_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
|
||||
@ -5,8 +5,8 @@
|
||||
{
|
||||
"idx": 0,
|
||||
"version": "6",
|
||||
"when": 1747914098702,
|
||||
"tag": "0000_panoramic_morlun",
|
||||
"when": 1754745234572,
|
||||
"tag": "0000_solid_lord_hawal",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
|
||||
@ -1,28 +1,10 @@
|
||||
import { sqliteTable, text } from 'drizzle-orm/sqlite-core'
|
||||
import { crudTimestamps } from './columnHelpers'
|
||||
|
||||
import { createUpdateTimestamps } from './columnHelpers'
|
||||
|
||||
export const appStateTable = sqliteTable('app_state', {
|
||||
key: text().primaryKey(),
|
||||
value: text({ mode: 'json' }).notNull(), // JSON field, drizzle handles serialization automatically
|
||||
description: text(), // Optional description field
|
||||
...crudTimestamps
|
||||
...createUpdateTimestamps
|
||||
})
|
||||
|
||||
export type AppStateTable = typeof appStateTable
|
||||
export type AppStateInsert = typeof appStateTable.$inferInsert
|
||||
export type AppStateSelect = typeof appStateTable.$inferSelect
|
||||
|
||||
// State key constants
|
||||
export const APP_STATE_KEYS = {
|
||||
DATA_REFACTOR_MIGRATION_STATUS: 'data_refactor_migration_status',
|
||||
// Future state keys can be added here
|
||||
// FIRST_RUN_COMPLETED: 'first_run_completed',
|
||||
// USER_ONBOARDING_COMPLETED: 'user_onboarding_completed',
|
||||
} as const
|
||||
|
||||
// Data refactor migration status interface
|
||||
export interface DataRefactorMigrationStatus {
|
||||
completed: boolean
|
||||
completedAt?: number
|
||||
version?: string
|
||||
}
|
||||
@ -4,7 +4,12 @@ const createTimestamp = () => {
|
||||
return Date.now()
|
||||
}
|
||||
|
||||
export const crudTimestamps = {
|
||||
export const createUpdateTimestamps = {
|
||||
createdAt: integer().$defaultFn(createTimestamp),
|
||||
updatedAt: integer().$defaultFn(createTimestamp).$onUpdateFn(createTimestamp)
|
||||
}
|
||||
|
||||
export const createUpdateDeleteTimestamps = {
|
||||
createdAt: integer().$defaultFn(createTimestamp),
|
||||
updatedAt: integer().$defaultFn(createTimestamp).$onUpdateFn(createTimestamp),
|
||||
deletedAt: integer()
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { index, sqliteTable, text } from 'drizzle-orm/sqlite-core'
|
||||
|
||||
import { crudTimestamps } from './columnHelpers'
|
||||
import { createUpdateTimestamps } from './columnHelpers'
|
||||
|
||||
export const preferenceTable = sqliteTable(
|
||||
'preference',
|
||||
@ -8,7 +8,7 @@ export const preferenceTable = sqliteTable(
|
||||
scope: text().notNull(), // scope is reserved for future use, now only 'default' is supported
|
||||
key: text().notNull(),
|
||||
value: text({ mode: 'json' }),
|
||||
...crudTimestamps
|
||||
...createUpdateTimestamps
|
||||
},
|
||||
(t) => [index('scope_name_idx').on(t.scope, t.key)]
|
||||
)
|
||||
|
||||
@ -1,34 +1,42 @@
|
||||
import dbService from '@data/db/DbService'
|
||||
import { APP_STATE_KEYS, appStateTable, DataRefactorMigrationStatus } from '@data/db/schemas/appState'
|
||||
import { appStateTable } from '@data/db/schemas/appState'
|
||||
import { loggerService } from '@logger'
|
||||
import { isDev } from '@main/constant'
|
||||
import BackupManager from '@main/services/BackupManager'
|
||||
import { IpcChannel } from '@shared/IpcChannel'
|
||||
import { eq } from 'drizzle-orm'
|
||||
import { app, BrowserWindow, ipcMain } from 'electron'
|
||||
import { app as electronApp } from 'electron'
|
||||
import fs from 'fs-extra'
|
||||
import { join } from 'path'
|
||||
|
||||
import icon from '../../../../build/icon.png?asset'
|
||||
import BackupManager from '../../services/BackupManager'
|
||||
import { PreferencesMigrator } from './PreferencesMigrator'
|
||||
import { PreferencesMigrator } from './migrators/PreferencesMigrator'
|
||||
|
||||
const logger = loggerService.withContext('MigrateService')
|
||||
const logger = loggerService.withContext('DataRefactorMigrateService')
|
||||
|
||||
export interface MigrationProgress {
|
||||
const DATA_REFACTOR_MIGRATION_STATUS = 'data_refactor_migration_status'
|
||||
|
||||
// Data refactor migration status interface
|
||||
interface DataRefactorMigrationStatus {
|
||||
completed: boolean
|
||||
completedAt?: number
|
||||
version?: string
|
||||
}
|
||||
|
||||
interface MigrationProgress {
|
||||
stage: string
|
||||
progress: number
|
||||
total: number
|
||||
message: string
|
||||
}
|
||||
|
||||
export interface MigrationResult {
|
||||
interface MigrationResult {
|
||||
success: boolean
|
||||
error?: string
|
||||
migratedCount: number
|
||||
}
|
||||
|
||||
export class MigrateService {
|
||||
private static instance: MigrateService | null = null
|
||||
class DataRefactorMigrateService {
|
||||
private static instance: DataRefactorMigrateService | null = null
|
||||
private migrateWindow: BrowserWindow | null = null
|
||||
private backupManager: BackupManager
|
||||
private backupCompletionResolver: ((value: boolean) => void) | null = null
|
||||
@ -63,7 +71,7 @@ export class MigrateService {
|
||||
// Only register the minimal IPC handlers needed for migration
|
||||
ipcMain.handle(IpcChannel.DataMigrate_CheckNeeded, async () => {
|
||||
try {
|
||||
return await this.checkMigrationNeeded()
|
||||
return await this.isMigrated()
|
||||
} catch (error) {
|
||||
logger.error('IPC handler error: checkMigrationNeeded', error as Error)
|
||||
throw error
|
||||
@ -143,96 +151,31 @@ export class MigrateService {
|
||||
}
|
||||
}
|
||||
|
||||
public static getInstance(): MigrateService {
|
||||
if (!MigrateService.instance) {
|
||||
MigrateService.instance = new MigrateService()
|
||||
public static getInstance(): DataRefactorMigrateService {
|
||||
if (!DataRefactorMigrateService.instance) {
|
||||
DataRefactorMigrateService.instance = new DataRefactorMigrateService()
|
||||
}
|
||||
return MigrateService.instance
|
||||
return DataRefactorMigrateService.instance
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if migration is needed
|
||||
*/
|
||||
async checkMigrationNeeded(): Promise<boolean> {
|
||||
async isMigrated(): Promise<boolean> {
|
||||
try {
|
||||
logger.info('Checking if migration is needed')
|
||||
|
||||
// 1. Check migration completion status
|
||||
const isMigrated = await this.isMigrationCompleted()
|
||||
if (isMigrated) {
|
||||
logger.info('Migration already completed')
|
||||
return false
|
||||
logger.info('Data Refactor Migration already completed')
|
||||
return true
|
||||
}
|
||||
|
||||
// 2. Check if there's old data that needs migration
|
||||
const hasOldData = await this.hasOldFormatData()
|
||||
|
||||
logger.info('Migration check result', {
|
||||
isMigrated,
|
||||
hasOldData
|
||||
})
|
||||
|
||||
return hasOldData
|
||||
return false
|
||||
} catch (error) {
|
||||
logger.error('Failed to check migration status', error as Error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if old format data exists
|
||||
*/
|
||||
private async hasOldFormatData(): Promise<boolean> {
|
||||
const hasReduxData = await this.checkReduxPersistData()
|
||||
const hasElectronStoreData = await this.checkElectronStoreData()
|
||||
|
||||
logger.debug('Old format data check', {
|
||||
hasReduxData,
|
||||
hasElectronStoreData
|
||||
})
|
||||
|
||||
return hasReduxData || hasElectronStoreData
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if Redux persist data exists
|
||||
*/
|
||||
private async checkReduxPersistData(): Promise<boolean> {
|
||||
try {
|
||||
// In Electron, localStorage data is stored in userData/Local Storage/leveldb
|
||||
// We'll check for the existence of these files as a proxy for Redux persist data
|
||||
const userDataPath = app.getPath('userData')
|
||||
const localStoragePath = join(userDataPath, 'Local Storage', 'leveldb')
|
||||
|
||||
const exists = await fs.pathExists(localStoragePath)
|
||||
logger.debug('Redux persist data check', { localStoragePath, exists })
|
||||
|
||||
return exists
|
||||
} catch (error) {
|
||||
logger.warn('Failed to check Redux persist data', error as Error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if ElectronStore data exists
|
||||
*/
|
||||
private async checkElectronStoreData(): Promise<boolean> {
|
||||
try {
|
||||
// ElectronStore typically stores data in config files
|
||||
const userDataPath = app.getPath('userData')
|
||||
const configPath = join(userDataPath, 'config.json')
|
||||
|
||||
const exists = await fs.pathExists(configPath)
|
||||
logger.debug('ElectronStore data check', { configPath, exists })
|
||||
|
||||
return exists
|
||||
} catch (error) {
|
||||
logger.warn('Failed to check ElectronStore data', error as Error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if migration is already completed
|
||||
*/
|
||||
@ -241,7 +184,7 @@ export class MigrateService {
|
||||
const result = await this.db
|
||||
.select()
|
||||
.from(appStateTable)
|
||||
.where(eq(appStateTable.key, APP_STATE_KEYS.DATA_REFACTOR_MIGRATION_STATUS))
|
||||
.where(eq(appStateTable.key, DATA_REFACTOR_MIGRATION_STATUS))
|
||||
.limit(1)
|
||||
|
||||
if (result.length === 0) return false
|
||||
@ -268,7 +211,7 @@ export class MigrateService {
|
||||
await this.db
|
||||
.insert(appStateTable)
|
||||
.values({
|
||||
key: APP_STATE_KEYS.DATA_REFACTOR_MIGRATION_STATUS,
|
||||
key: DATA_REFACTOR_MIGRATION_STATUS,
|
||||
value: migrationStatus, // drizzle handles JSON serialization automatically
|
||||
description: 'Data refactoring migration status from legacy format (ElectronStore + Redux persist) to SQLite',
|
||||
createdAt: Date.now(),
|
||||
@ -318,15 +261,14 @@ export class MigrateService {
|
||||
sandbox: false,
|
||||
webSecurity: false,
|
||||
contextIsolation: true
|
||||
},
|
||||
...(process.platform === 'linux' ? { icon } : {})
|
||||
}
|
||||
})
|
||||
|
||||
// Load the migration window
|
||||
if (app.isPackaged) {
|
||||
this.migrateWindow.loadFile(join(__dirname, '../renderer/dataMigrate.html'))
|
||||
if (isDev && process.env['ELECTRON_RENDERER_URL']) {
|
||||
this.migrateWindow.loadURL(process.env['ELECTRON_RENDERER_URL'] + '/dataRefactorMigrate.html')
|
||||
} else {
|
||||
this.migrateWindow.loadURL('http://localhost:5173/dataMigrate.html')
|
||||
this.migrateWindow.loadFile(join(__dirname, '../renderer/dataRefactorMigrate.html'))
|
||||
}
|
||||
|
||||
this.migrateWindow.once('ready-to-show', () => {
|
||||
@ -619,4 +561,4 @@ export class MigrateService {
|
||||
}
|
||||
|
||||
// Export singleton instance
|
||||
export const migrateService = MigrateService.getInstance()
|
||||
export const dataRefactorMigrateService = DataRefactorMigrateService.getInstance()
|
||||
@ -3,7 +3,7 @@ import { preferenceTable } from '@data/db/schemas/preference'
|
||||
import { loggerService } from '@logger'
|
||||
import { and, eq } from 'drizzle-orm'
|
||||
|
||||
import { configManager } from '../../services/ConfigManager'
|
||||
import { configManager } from '../../../../services/ConfigManager'
|
||||
|
||||
const logger = loggerService.withContext('PreferencesMigrator')
|
||||
|
||||
@ -1,86 +0,0 @@
|
||||
/**
|
||||
* Auto-generated migration index
|
||||
* Generated at: 2025-08-09T07:20:05.909Z
|
||||
*
|
||||
* This file is automatically generated from classification.json
|
||||
* To update this file, modify classification.json and run:
|
||||
* node .claude/data-classify/scripts/generate-migration.js
|
||||
*
|
||||
* === AUTO-GENERATED CONTENT START ===
|
||||
*/
|
||||
|
||||
// LEGACY MIGRATION SYSTEM - COMMENTED OUT
|
||||
// These files have been replaced by PreferencesMigrator.ts
|
||||
// import { ElectronStoreMigrator } from './electronStoreToPreferences'
|
||||
// import { ReduxMigrator } from './reduxToPreferences'
|
||||
import { loggerService } from '@logger'
|
||||
|
||||
const logger = loggerService.withContext('MigrationManager')
|
||||
|
||||
export interface MigrationResult {
|
||||
success: boolean
|
||||
migratedCount: number
|
||||
errors: Array<{
|
||||
key: string
|
||||
error: string
|
||||
}>
|
||||
source: 'electronStore' | 'redux'
|
||||
}
|
||||
|
||||
export interface MigrationSummary {
|
||||
totalItems: number
|
||||
successCount: number
|
||||
errorCount: number
|
||||
electronStore: MigrationResult
|
||||
redux: MigrationResult
|
||||
}
|
||||
|
||||
export class MigrationManager {
|
||||
// LEGACY MIGRATION SYSTEM - COMMENTED OUT
|
||||
// private electronStoreMigrator: ElectronStoreMigrator
|
||||
// private reduxMigrator: ReduxMigrator
|
||||
|
||||
constructor() {
|
||||
// this.electronStoreMigrator = new ElectronStoreMigrator()
|
||||
// this.reduxMigrator = new ReduxMigrator()
|
||||
logger.warn('MigrationManager is deprecated. Use PreferencesMigrator instead.')
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行完整的preferences迁移
|
||||
* @returns 迁移摘要
|
||||
*/
|
||||
async migrateAllPreferences(): Promise<MigrationSummary> {
|
||||
logger.warn('MigrationManager.migrateAllPreferences is deprecated. Use PreferencesMigrator instead.')
|
||||
|
||||
// Return a placeholder summary since the actual migration is handled by PreferencesMigrator
|
||||
const summary: MigrationSummary = {
|
||||
totalItems: 0,
|
||||
successCount: 0,
|
||||
errorCount: 0,
|
||||
electronStore: { success: false, migratedCount: 0, errors: [], source: 'electronStore' },
|
||||
redux: { success: false, migratedCount: 0, errors: [], source: 'redux' }
|
||||
}
|
||||
|
||||
return summary
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证迁移结果
|
||||
* @param summary 迁移摘要
|
||||
* @returns 是否验证成功
|
||||
*/
|
||||
async validateMigration(_summary: MigrationSummary): Promise<boolean> {
|
||||
logger.warn('MigrationManager.validateMigration is deprecated. Use PreferencesMigrator validation instead.')
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// === AUTO-GENERATED CONTENT END ===
|
||||
|
||||
/**
|
||||
* 生成统计:
|
||||
* - 总迁移项: 158
|
||||
* - ElectronStore项: 4
|
||||
* - Redux项: 154
|
||||
*/
|
||||
@ -9,7 +9,7 @@ import { loggerService } from '@logger'
|
||||
import { electronApp, optimizer } from '@electron-toolkit/utils'
|
||||
import dbService from '@data/db/DbService'
|
||||
import { replaceDevtoolsFont } from '@main/utils/windowUtil'
|
||||
import { app } from 'electron'
|
||||
import { app, dialog } from 'electron'
|
||||
import installExtension, { REACT_DEVELOPER_TOOLS, REDUX_DEVTOOLS } from 'electron-devtools-installer'
|
||||
|
||||
import { isDev, isLinux, isWin } from './constant'
|
||||
@ -27,7 +27,7 @@ import selectionService, { initSelectionService } from './services/SelectionServ
|
||||
import { registerShortcuts } from './services/ShortcutService'
|
||||
import { TrayService } from './services/TrayService'
|
||||
import { windowService } from './services/WindowService'
|
||||
import { migrateService } from './data/migrate/MigrateService'
|
||||
import { dataRefactorMigrateService } from './data/migrate/dataRefactor/DataRefactorMigrateService'
|
||||
import process from 'node:process'
|
||||
|
||||
const logger = loggerService.withContext('MainEntry')
|
||||
@ -102,14 +102,35 @@ if (!app.requestSingleInstanceLock()) {
|
||||
app.quit()
|
||||
process.exit(0)
|
||||
} else {
|
||||
dbService.migrateDb().then(async () => {
|
||||
await dbService.migrateSeed('preference')
|
||||
})
|
||||
|
||||
// This method will be called when Electron has finished
|
||||
// initialization and is ready to create browser windows.
|
||||
// Some APIs can only be used after this event occurs.
|
||||
app.whenReady().then(async () => {
|
||||
// First of all, init & migrate the database
|
||||
await dbService.migrateDb()
|
||||
await dbService.migrateSeed('preference')
|
||||
|
||||
// Data Refactor Migration
|
||||
// Check if data migration is needed BEFORE creating any windows
|
||||
try {
|
||||
const isMigrated = await dataRefactorMigrateService.isMigrated()
|
||||
if (!isMigrated) {
|
||||
logger.info('Data Refactor Migration needed, starting migration process')
|
||||
await dataRefactorMigrateService.runMigration()
|
||||
logger.info('Migration completed, app will restart automatically')
|
||||
// Migration service will handle app restart, no need to continue startup
|
||||
return
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Migration process failed', error as Error)
|
||||
dialog.showErrorBox(
|
||||
'Fatal Error: Data Refactor Migration Failed',
|
||||
`The application could not start due to a critical error during data migration.\n\nPlease contact support or try restoring data from a backup.\n\nError details:\n${(error as Error).message}`
|
||||
)
|
||||
app.quit()
|
||||
return
|
||||
}
|
||||
|
||||
// Set app user model id for windows
|
||||
electronApp.setAppUserModelId(import.meta.env.VITE_MAIN_BUNDLE_ID || 'com.kangfenmao.CherryStudio')
|
||||
|
||||
@ -119,22 +140,6 @@ if (!app.requestSingleInstanceLock()) {
|
||||
app.dock?.hide()
|
||||
}
|
||||
|
||||
// Check if data migration is needed BEFORE creating any windows
|
||||
try {
|
||||
const needsMigration = await migrateService.checkMigrationNeeded()
|
||||
if (needsMigration) {
|
||||
logger.info('Migration needed, starting migration process')
|
||||
await migrateService.runMigration()
|
||||
logger.info('Migration completed, app will restart automatically')
|
||||
// Migration service will handle app restart, no need to continue startup
|
||||
return
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Migration process failed', error as Error)
|
||||
// Continue with normal startup even if migration fails
|
||||
// The user can retry migration later or use backup recovery
|
||||
}
|
||||
|
||||
// Only create main window if no migration was needed or migration failed
|
||||
const mainWindow = windowService.createMainWindow()
|
||||
|
||||
|
||||
@ -3,14 +3,14 @@
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Cherry Studio - Data Migration</title>
|
||||
<title>Cherry Studio - Data Refactor Migration</title>
|
||||
<meta http-equiv="Content-Security-Policy"
|
||||
content="default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:;" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
</head>
|
||||
|
||||
<body id="root">
|
||||
<script type="module" src="/src/windows/dataMigrate/entryPoint.tsx"></script>
|
||||
<script type="module" src="/src/windows/dataRefactorMigrate/entryPoint.tsx"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Loading…
Reference in New Issue
Block a user